A Suggestion (please read and respond)
Alex Martelli
aleaxit at yahoo.com
Mon Oct 30 15:35:31 EST 2000
"Courageous" <jkraska1 at san.rr.com> wrote in message
news:39FDAE7D.2259B2EC at san.rr.com...
[snip]
> strict class Joe:
> i = 3
> j = Joe()
> j.j = 1
>
> >>>> Attribute error: strict classes only support instance attributes
> which also exist as class attributes. Valid instance attributes are:
> 'i' (which is an integer in its class context)
>
> You could do something similar with every possible namespace, although
> I haven't thought out what the syntax might be for modules...
>
> Note for classes you can, by overriding the set attr method, implement
> this now.
Very, very true. Moreover, you can do it by mix-in inheritance
if you don't need to have your own special meaning for
__setattr__ (if you do, you will need explicit delegation).
For example, this gets close:
-- cut: strict.py
class Strict:
def __setattr__(self, name, value):
if hasattr(self.__class__,name):
self.__dict__[name]=value
else:
names = [x for x in self.__class__.__dict__.keys()
if not x.startswith('__')]
names.sort()
message = ("Class %s is strict: only attributes %s can be set" %
(self.__class__.__name__, names))
raise AttributeError,message
-- end of cut
>>> import strict
>>> class Mine(strict.Strict):
a=1; b=2; c="foo"; d=()
>>> x=Mine()
>>> x.a=23
>>> x.z='foo'
Traceback (innermost last):
File "<pyshell#20>", line 1, in ?
x.z='foo'
File "D:\Python20\strict.py", line 11, in __setattr__
raise AttributeError,message
AttributeError: Class Mine is strict: only attributes ['a', 'b', 'c', 'd']
can be set
However, the message is misleading for _inherited_ attributes (a bit too
strict, let's say...):
>>> class Yours(Mine):
z=45; y='wep'
>>> y=Yours()
>>> y.z='plop'
>>> y.a=23
>>> y.n=42
Traceback (innermost last):
File "<pyshell#48>", line 1, in ?
y.n=42
File "D:\Python20\strict.py", line 11, in __setattr__
raise AttributeError,message
AttributeError: Class Yours is strict: only attributes ['y', 'z'] can be set
>>>
It's not true -- attribute a can be set as well, as we have just
demonstrated! -- but it ain't too hard to fix... left as an
exercise to the reader!-) [these metaprogramming tricks
are fascinating, though I think their status is close to what
Zen thinks of metaphysical reflections -- just a mind-
obstacle in the quest for true simplicity...:-)]
Alex
Thinking up strategies for that to be arranged gets
interesting -- looking up a name in the graph of
base classes each time, recursively, is not too hard
of course:
def isnameok_inclass(klass, name):
if klass.__dict__.has_key(name):
return klass
for super in klass.__bases__:
isokthere=isnameok_inclass(super,name)
if isokthere: return isokthere
return None
def isnameok(object, name):
return isnameok_inclass(object.__class__, name)
and change the line in class Strict
if self.__class__.__dict__.has_key(name):
into
if isnameok(self, name):
but optimizing that is more interesting. For
example, if we can assume that a class's bases
are not changed during runtime (or if special
re-processing can be required if they do), we
could compute an '_allbases' field in a class
the first time is needed:
def allbasesof(klass):
if not klass.__dict__.has_key('_allbases'):
all = list(klass.__bases__)
for super in klass.__bases__:
all.extend(allbasesof(super))
klass._allbases = all
return klass._allbases
More information about the Python-list
mailing list