Jeff Shannon said unto the world upon 2005-02-15 21:20:
On Tue, 15 Feb 2005 17:19:37 -0500, Brian van den Broek
<[EMAIL PROTECTED]> wrote:


My Node class defines a _parse method which separates out the node
header, and sends those lines to a _parse_metadata method. This is
where the elif chain occurs -- each line of the metadata starts with a
tag like "dt=" and I need to recognize each tag and set the
appropriate Node object attribute, such as .document_type. (I do not
want to rely on the unhelpful names for the tags in the file format,
preferring more self-documenting attribute names.)


In addition to using setattr(), I'd take a slightly different approach
to this.  (This may just be a matter of personal style, and is not as
clearly advantageous as using setattr() instead of exec, but...)

Hi Jeff and all,

I am *pretty* sure I followed what you meant, Jeff. Thank you for the suggestions! I don't think they will fit with my situation, but that I think so might say more about my present level of understanding of OOP and design issues than about either the suggestions or the situation. :-)

.class Node(object):
.    metadata = {'dt': 'document_type', 'something': 'some_other_field', ...}
.    def __init__(self):  # ....
.    def update(self, **kwargs):
.        for key, value in kwargs.items():
.        try:
.            attr_name = self.metadata[key]
.        except KeyError:
.            raise ValueError("Invalid field type '%s'" % key)
.        setattr(self, attr_name, value)

For starters, I've made metadata a class attribute rather than an
unconnected dictionary.  This seems conceptually nicer to me.

The problem is that my Node instance live in a TP_file class instance, and the way my code is now, the TP_file instance also needs to see the metadata dict. There are a few tags, which if present in any Node of the file make me want to treat the entire file a bit differently. (Of course, here is the place where my novice-designer status is most likely to be bitting me.) So, that's why I have it as a module level object, rather than within a class. (I do, however, see your point about it being neater.)



In addition, update() can now modify several attributes at once, at
the cost of a bit of extra parsing up front.

Supposing that your node header looks like this:

.header = "dt=text/plain;something=some_value;last=some_other_thing_here"

Now, we can break that into fields, and then split the fields into a
name and a value --

.tags = {}
.for field in header.split(';'):
.    name, value = field.split('=')
.    tags[name] = value
.
.n = Node()
.n.update(**tags)

You can even simplify this a bit more, by rewriting the __init__():

.    def __init__(self, **kwargs):
.        if kwargs:
.            self.update(**kwargs)

Now you can create and update in a single step:

.n = Node(**tags)

The metadata all occurs one element to a line in my original file. I've got the TP_file class breaking the nodes up and sending the contents to new Node instances (as Alan suggested in my previous thread). The Node instance has a parse method that reads the node contents line by line and sends the appropriate lines to the parse_metadata method. (All lines before a designated `header-ending' line.) Maybe I'm still missing a better way, but as I am processing line by line, each line with one element, I don't see how to use this cool looking multiple elements at once approach. (The other complication that I didn't mention is that the parse_metadata method has to do more than just store the metadata -- some elements must be converted to ints, others left as strings, and still others can have multiple instances in a single Node, so rather than be set they must be appended to an attribute list, etc. The setattr way has taken me from 20 elifs to just 4, though :-) )


At any rate, my whole code is (perhaps wrongly) organized around logical-line based processing.

You could also put all of the splitting into fields in a method, and
when __init__ gets a single string as its argument simply pass it to
that method and update with the results...

--Jeff Shannon

Anyway, such are the reasons I'm not sure the suggestions will work in my situation. I'm glad to have seen them, though, and am going to save them for the point where I actually have the whole program working and can think about large-scale refactoring. I may well then find that my current uncertainty is unwarranted. But I'd like to make the beast live before I make it thrive :-)


Thanks again, and best,

Brian vdB

_______________________________________________
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor

Reply via email to