Generic constructors and duplication of internal Python logic

Peter Otten __peter__ at web.de
Tue Apr 20 03:51:39 EDT 2004


John J. Lee wrote:

> Peter Otten <__peter__ at web.de> writes:
> 
>> John J. Lee wrote:
> [...]
>> You could use a noop method check_attrs() to define the argspec.
>> check_attrs() is then called from the mixin's __init__() just to check
>> that the parameters comply.
>> 
>> import inspect
>> 
>> def make_attrspec(f):
>>     a = inspect.getargspec(f)
>>     names = a[0]
>>     if names[0] in ["self", "cls"]:
>>         # XXX for now relies on naming convention
>>         del names[0]
>>     defaults = a[3]
>>     for i in range(-1, -len(defaults)-1, -1):
>>         names[i] = names[i], defaults[i]
>>     return names
>> 
>> class ArgsMixin:
>>     def __init__(self, *args, **kwds):
>>         self.check_attrs(*args, **kwds)
>> 
>> class Blah(ArgsMixin):
>>     def check_attrs(self, foo, bar, baz, optional1="first",
>> optional2="second"):
>>         pass
>>     attr_spec = make_attrspec(check_attrs)
> 
> Clever.  But how to get __init__ to assign the arguments to the
> instance?
> 
> b = Blah(foo=1, bar=2, optional1=4)
> assert b.foo, b.bar, b.optional1 = 1, 2, 4
> 
> 
> That half of the problem is missing in your solution.

I'll give it a try (untested):

class ArgsMixin:
    def __init__(self, *args, **kwds):
        self.check_attrs(*args, **kwds)
        # positionals provided
        for n, v in zip(self.attr_spec, args):
            setattr(self, n, v)
        # positionals using defaults
        for nv in self.attr_spec[len(args):]:
            if not isinstance(nv, basestring):
                n, v = nv
                if not n in kwds:
                    setattr(self, n, v)
        # keyword args
        for n, v in kwds.iteritems():
            setattr(self, n, v)

The clumsy basestring check could be avoided if you either split attr_spec
in the tuple/non-tuple parts or precalculate the first non-tuple position.

Peter




More information about the Python-list mailing list