hmm, lets call it: generic __init__ problem

Peter Otten __peter__ at web.de
Wed Feb 18 10:33:41 CET 2004


paul kölle wrote:

> in the course of writing a small app, I tried to design a class, which
> would allow to derive its behaviour solely from its name, so that I
> would be able to write one abstract class with the logic and get
> different objects/instances by subclassing with appropriate names.
> Consider the following:

[quotes as mutilated by my news reader :-(]

> ATTRS = {'one':['attr1', 'attr2'],
> 'two':['attr3','attr4'],
> 'three':['attr5','attr6'],
> 'four':['attr7','attr8']}
> 
> 
> class one:
> def __init__(self, *args, **kwargs):
> ## get allowed attributes...
> for attr in ATTRS[self.__class__.__name__]:
> self.__dict__[attr] = ''
> 
> ## unknown attributes are silently ignored...
> for item in kwargs.keys():
> if self.__dict__.has_key( item ):
> self.__dict__[item] = kwargs[item]
> else:
> pass

Superfluous else: pass

> ## init all parents...
> parents = self.__class__.__bases__
> if parents:
> for i in range(len(parents)):
> apply(parents[i].__name__.__init__,\                                                          
> (self,)+args, kwargs)

In current python:

for parent in  parents:
    parent.__name__.__init__(self, *args, **kwargs)

However, you are calling the __init__() method of a string (parent.__name__)
which is a noop as strings are immutable (I'm surprised it didn't fail).
I suppose you intended to call parent.__init__() which would result in
infinite recursion as you determine the class to operate on by
self.__class__ which will always be the same.

I think this is what you want:

ATTRS = {'one':['attr1', 'attr2'],
         'two':['attr3','attr4'],
         'three':['attr5','attr6'],
         'four':['attr7','attr8']}

class one:
    def __init__(self, **kwargs):
        ## get allowed attributes...
        classes = [self.__class__]
        while classes:
            cls = classes.pop(0)
            for attr in ATTRS[cls.__name__]:
                self.__dict__[attr] = ''
            classes.extend(cls.__bases__)

        ## unknown attributes are silently ignored...
        for key, value in kwargs.iteritems():
            if key in self.__dict__:
                self.__dict__[key] = value

class two(one):
    def foo(self):
        pass

class three(one):
    def bar(self):
        pass

class four(two, three):
    def wiskey_bar(self):
        pass

params = dict(attr1="a", attr3="b", attr5="c", attr7="d")
for klass in [one, two, three, four]:
    obj = klass(**params)
    print klass.__name__
    print "\t", [a for a in dir(obj) if not a.startswith("_")]

> Apart from the obvious mistake I can't figure out:
> 1) Is this intelligent at all?

Is there a polite way of saying no?
Seriously, have a look at the tutorial to get uptodate with the current
python features, then set yourself a real task and try to solve it in the
simplest and cleanest manner. I am confident that you will *not* need
multiple inheritance or attributes with pointless default values.
IMHO silently ignoring anything is strongly against python's philosophy.

> 2) Is there a better way to do it?

I'm sure there would be if only I knew what *it* is meant to be.

> 3) How do you change tabwidth in mozilla mail?

No idea, but changing from tabs to spaces is urgent, as you can see from the
quotes.

Peter



More information about the Python-list mailing list