mixin helper class for unknown attribute access?

Steven D'Aprano steve at REMOVETHIScyber.com.au
Mon Oct 31 08:44:36 EST 2005


On Mon, 31 Oct 2005 12:47:16 +0000, Alex Hunsley wrote:

> Sorry, as I noted in another reply not long ago, I was having a 'braino' 
> and not saying what I actually meant!
> What I was talking about was the accidental _setting_ of the wrong 
> attribute.
> And the mixin class I'm looking for is one that could be told what were 
> valid attributes for the class, 

Who decides what are valid attributes for a class? The class writer, or
the class user who may want to use it in ways the writer never imagined?


> and would then catch the situation where 
> you mis-spelt an attribute name when setting an attrib.

If all you care about is preventing developers from adding any new
attributes at run time, you can do something like this:

# warning: untested
class Example:
    def __init__(self, data):
        self.__dict__['data'] = data
    def __setattr__(self, name, value):
        if self.__dict__.has_key(name):
            self.__dict__[name] = value
        else:
            raise AttributeError

except that the developers will then simply bypass your code:

p = Example(None)
p.__dict__['surprise'] = 1
p.surprise

Trying to prevent setting new attributes is a pretty heavy-handed act just
to prevent a tiny subset of errors. Many people argue strongly that even
if you could do it, it would be pointless -- or at least, the cost is far
greater than whatever small benefit there is.

But, if you insist, something like this:

# Warning: untested.
class Declare:
    def __init__(self, names):
        """names is a list of attribute names which are allowed.
        Attributes are NOT initialised.
        """
        self.__dict__['__ALLOWED'] = names
    def __setattr__(self, name, value):
        if name in self.__ALLOWED:
            self.__dict__[name] = value
        else:
            raise AttributeError("No such attribute.")

If you want to initialise your attributes at the same time you declare
them, use:

# Warning: untested.
class DeclareInit:
    def __init__(self, names):
        """names is a dictionary of attribute names/values which are
        allowed.
        """
        self.__dict__ = names
    def __setattr__(self, name, value):
        if self.__dict__.has_key(name):
            self.__dict__[name] = value
        else:
            raise AttributeError("No such attribute.")

Of the two approaches, I would say the second is marginally less of a bad
idea.

-- 
Steven.




More information about the Python-list mailing list