whats new in 2.2 (was A modest indentation proposal)
Quinn Dunkan
quinn at chunder.ugcs.caltech.edu
Mon Dec 3 19:04:28 EST 2001
> Here is my current decorator pattern:
>
> class Decorator:
> """An abstract Decorator class based on one posted to comp.lang.python
> by Rainer Deyke.
> """
> def __init__(self, decorated):
> self._decorated = decorated
> # add some data attributes you want
> def __getattr__(self, name):
> return getattr(self._decorated, name)
> def __call__(self, *args, **kwargs):
> self._decorated(*args, **kwargs)
> # Override other operators too
Yeah, the "Override other operators too" part is the problem. You have to
make sure you get all of them. With the above if you decorate a list,
len(lst) will throw an exception, since getattr([], '__len__') fails.
Here's my decorator that manages to avoid __getattr__ alltogether:
class Exclusive_file:
class Already_locked(IOError): pass
def __init__(self, filename):
self.fp = open(filename, 'r+')
try:
fcntl.lockf(self.fp.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError, e:
if e.errno == errno.EAGAIN:
raise self.Already_locked(filename)
else:
raise
# delegate methods without using a slow __setattr__
for attr in dir(self.fp):
if not hasattr(self, attr):
setattr(self, attr, getattr(self.fp, attr))
Making this change speeded the program up considerably, since readline() is so
popular. It's not trustworthy in general, since dir() doesn't tell the whole
story with regards to inheritance, etc. Still, it works ok for file objects.
Once again, dir() has changed in 2.2.
You wouldn't want to use this for a generic delegator, though, because things
break horribly if someone has dynamic attributes.
> This relies on the fact that my __getattr__ will not get called if
> python already finds the attribute. What am I supposed to do in 2.2
> with not classic classes, if this is the exact behaviour I want?
Classic classes are only activated when you inherit from 'object'. In any
case, the 2.2 change that will make you happy here is that [] now has a
__len__ attribute.
2.2 also seems to have a __getattribute__ that *always* gets called. It's
like __builtins__ vs. __builtin__, it looks like a typo but actually there's
an important difference. *sigh*
Of course, if it had a 'len' attribute, we could get rid of the ugly __magic__
method and redefine the len() builtin as 'def len(x): x.len()'. Because of
backwards compatibility, though, that will likely never happen.
More information about the Python-list
mailing list