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