Re: [Python-ideas] possible attribute-oriented class
06-09-2009 o 20:20:21 Ethan Furman <ethan@stoneleaf.us> wrote:
In the dbf module I wrote, I use both the attribute access and the key lookup. The attribute access is great for interactive use, and for all the routines that play with the tables we have at work, where all the field names are indeed known at compile (aka coding) time. On the other hand, some routines don't know which fields they'll mucking about with, and so the key access is vital for them.
Of course, I could have done the whole thing using key access, and I did have to impose some restrictions on method names so they wouldn't clash with possible field names, but I love being able to type
current_record.full_name == last_record.full_name
instead of
current_record['full_name'] == last_record['full_name']
Me too, and I suppose many people too... The latter: * makes your code less readable if there is high density of such expressions; * makes typing much more strenuous/irritating -- what is not very important in case of advanced development (when time of typing is short in relation to time of thinking/reading/testing) but becomes quite important in case of scripting (which is still important area of Python usage). -- Jan Kaliszewski (zuo) <zuo@chopin.edu.pl>
On Mon, 7 Sep 2009 09:37:35 am Jan Kaliszewski wrote:
06-09-2009 o 20:20:21 Ethan Furman <ethan@stoneleaf.us> wrote:
... I love being able to type
current_record.full_name == last_record.full_name
instead of
current_record['full_name'] == last_record['full_name']
Me too, and I suppose many people too...
The latter:
* makes your code less readable if there is high density of such expressions;
* makes typing much more strenuous/irritating -- what is not very important in case of advanced development (when time of typing is short in relation to time of thinking/reading/testing) but becomes quite important in case of scripting (which is still important area of Python usage).
If you have a large number of such expressions, what's wrong with this? FNAME = "full_name" # Define the string in one place only. current_record[FNAME] == last_record[FNAME] # Use it in many places. Not only is it shorter to use, but it's easy to change the key "full_name" to (say) "complete_name" or "volledige_naam" with one edit, and without mistakenly changing some other string which just happens to match the key. (I don't know about others, but when I'm first working on a piece of code, and before I settle on an API or database schema, I often change field names two or three times before I settle in on the final version.) In any case, while I accept that this is sometimes useful, I also think that it's a something which is simple enough to add to your classes when necessary with just a few lines -- all you really need are the __*attr__ methods, everything else is superfluous. If you're doing this a lot, avoid boilerplate with a class decorator. Here's an untested minimalistic version which probably does everything necessary: def add_attr(cls): """Class decorator which adds attribute access to mappings.""" def __getattr__(self, name): return self[name] def __setattr__(self, name, value): self[name] = value def __delattr__(self, name): del self[name] for func in (__getattr__, __setattr__, __delattr__): setattr(cls, func.__name__, func) return cls Fields of an object (attributes) and keys of a mapping are generally for different purposes, and I'm not sure we should encourage people to conflate the two. I think this belongs in the cookbook, not the standard library. -- Steven D'Aprano
08-09-2009 o 02:15:10 Steven D'Aprano <steve@pearwood.info> wrote:
On Mon, 7 Sep 2009 09:37:35 am Jan Kaliszewski wrote:
06-09-2009 o 20:20:21 Ethan Furman <ethan@stoneleaf.us> wrote:
... I love being able to type
current_record.full_name == last_record.full_name
instead of
current_record['full_name'] == last_record['full_name']
Me too, and I suppose many people too...
The latter:
* makes your code less readable if there is high density of such expressions;
* makes typing much more strenuous/irritating -- what is not very important in case of advanced development (when time of typing is short in relation to time of thinking/reading/testing) but becomes quite important in case of scripting (which is still important area of Python usage).
If you have a large number of such expressions, what's wrong with this?
a['xyz'] = something['blablabla'] + somethingelse['foobar'] b['ababababa'] += afun(bobo['dodo']['kookoo'] * pofopofo['gh'][0]['a']) cupu['abc'] = (kukumunu['bo'], kukumunu['kuu'].mbmbmb['lalala']) a.xyz = something.blablabla + somethingelse.foobar b.ababababa += afun(bobo.dodo.kookoo * pofopofo.gh[0].a) cupu.abc = (kukumunu.bo, kukumunu.kuu.mbmbmb.lalala) For me the latter is definitely easier to read and understand.
FNAME = "full_name" # Define the string in one place only. current_record[FNAME] == last_record[FNAME] # Use it in many places.
Not only is it shorter to use, but it's easy to change the key "full_name" to (say) "complete_name" or "volledige_naam" with one edit, and without mistakenly changing some other string which just happens to match the key.
You are right, but it's a bit different story... I don't say that attr access is always better than key access -- but only that sometimes it is.
(I don't know about others, but when I'm first working on a piece of code, and before I settle on an API or database schema, I often change field names two or three times before I settle in on the final version.)
Me too! :)
In any case, while I accept that this is sometimes useful, I also think that it's a something which is simple enough to add to your classes when necessary with just a few lines -- all you really need are the __*attr__ methods, everything else is superfluous. If you're doing this a lot, avoid boilerplate with a class decorator. Here's an untested minimalistic version which probably does everything necessary:
def add_attr(cls): """Class decorator which adds attribute access to mappings.""" def __getattr__(self, name): return self[name] def __setattr__(self, name, value): self[name] = value def __delattr__(self, name): del self[name] for func in (__getattr__, __setattr__, __delattr__): setattr(cls, func.__name__, func) return cls
I'd add to it also dict-like iteration (__iter__(), _keys(), _values(), _items()) and __str__ adjusted to nice nested representation (like in some posts in this thread, e.g. my proposition).
Fields of an object (attributes) and keys of a mapping are generally for different purposes, and I'm not sure we should encourage people to conflate the two. I think this belongs in the cookbook, not the standard library.
I think it depends how often people need to implement such boiler-plate code for themselves. Now I see that this thread is not very popular, so indeed maybe you are right... Though it'd be nice to have OOTB such a factory in `collections` module... Cheers, *j -- Jan Kaliszewski (zuo) <zuo@chopin.edu.pl>
On Mon, Sep 7, 2009 at 9:02 PM, Jan Kaliszewski<zuo@chopin.edu.pl> wrote:
08-09-2009 o 02:15:10 Steven D'Aprano <steve@pearwood.info> wrote:
... what's wrong with this?
a['xyz'] = something['blablabla'] + somethingelse['foobar'] b['ababababa'] += afun(bobo['dodo']['kookoo'] * pofopofo['gh'][0]['a']) cupu['abc'] = (kukumunu['bo'], kukumunu['kuu'].mbmbmb['lalala'])
a.xyz = something.blablabla + somethingelse.foobar b.ababababa += afun(bobo.dodo.kookoo * pofopofo.gh[0].a) cupu.abc = (kukumunu.bo, kukumunu.kuu.mbmbmb.lalala)
For me the latter is definitely easier to read and understand.
I would describe it as "less difficult" rather than "easier". My biggest problem is that at that stage, I'm still typing raw, and inclined to make typos. The difference between fname and fnam won't be caught either way, but field access at least keeps me from forgetting quotes, or forgetting them at one end.
... I often change field names two or three times before I settle in on the final version.
And often because of an ambiguity with another field that I hadn't originally thought to name. Neither solution fixes this, but attribute access is slightly easier to change.
[recipe to simplify attr-access]
I think it depends how often people need to implement such boiler-plate code for themselves.
Attribute access is clearly better -- except for one thing. While I'm doing this, I'm still in exploratory mode, and I *will* need to clean up the API if I ever want better than quick-and-dirty. If the quick-and-dirty is already using attribute access, that makes the transition a bit trickier. If the quick-and-dirty is using dict access, at least I have a clear marker. -jJ
participants (4)
-
Jan Kaliszewski
-
Jim Jewett
-
Stephen J. Turnbull
-
Steven D'Aprano