Generic constructors and duplication of internal Python logic

Robert Brewer fumanchu at amor.org
Fri Apr 23 13:00:02 EDT 2004


Peter Otten wrote:
> def setLocals(d, selfName="self"):
>     self = d.pop(selfName)
>     for n, v in d.iteritems():
>         setattr(self, n, v)
> 
> class Demo(object):
>     def __init__(self, foo, bar, baz=2, bang=3):
>         setLocals(locals())

*Very* nice and clean.

John, if you still want the mixin (to avoid have to call setLocals in
every __init__, you could try a mixin like this (tested just enough to
post without egg on my face):

class ArgMixin(object):
    def __new__(cls, *args, **kwargs):
        inst = object.__new__(cls, *args, **kwargs)
        initargs = list(cls.__init__.func_code.co_varnames)
        # Remove 'self' from initargs
        initargs.pop(0)
        defaults = list(cls.__init__.func_defaults)
        
        # Set provided positional arguments as attributes of instance
        for arg in args:
            name = initargs.pop(0)
            setattr(inst, name, arg)
        
        # Set keyword arguments as attributes of instance,
        # using defaults if no value was passed.
        while initargs:
            name = initargs.pop(0)
            default = defaults.pop(0)
            setattr(inst, name, kwargs.get(name, default))
        
        return inst

class Demo(ArgMixin):
    def __init__(self, foo, bar, baz=2, bang=3):
        pass


...you would have to be careful when/if overriding __new__ in a
subclass. Also, __init__ can still change those attributes. I'm sure
someone will find something wrong with it* ;) but the idea is sound, and
uses some of Python's "internal logic" that you mentioned.


Robert Brewer
MIS
Amor Ministries
fumanchu at amor.org

* For example, I didn't chase down funky calls like Demo(bar=3,
foo="d'oh!"), which exhaust the defaults list.




More information about the Python-list mailing list