Frage

Es scheint, dass oft __init__ Methoden ähnlich sind dies:

def __init__(self, ivar1, ivar2, ivar3):
    self.ivar1 = ivar1
    self.ivar2 = ivar2
    self.ivar3 = ivar3

Gibt es irgendwie, die Argumente in eine Liste zu machen (ohne auf *args oder **kwargs) und dann setattr mit den Instanzvariablen zu setzen, mit dem Namen des Parameters und das Argumente übergeben? Und vielleicht die Liste in Scheiben schneiden, z.B. Sie müssen zumindest schneiden es [1:], weil Sie nicht self.self wollen.

(eigentlich ich denke, es müßte ein Wörterbuch sein, den Namen und den Wert zu halten)

wie folgt aus:

def __init__(self, ivar1, ivar2, ivar3, optional=False):
    for k, v in makedict(self.__class__.__init__.__args__): # made up __args__
        setattr(self, k, v)

Danke!

Als Reaktion auf Unknown Antwort, fand ich dies funktioniert:

Class A(object):
    def __init__(self, length, width, x):
        self.__dict__.update(dict([(k, v) for k, v in locals().iteritems() if k != 'self']))

oder

Class A(object):
    def __init__(self, length, width, x):
        self.__dict__.update(locals())
        del self.__dict__['self']

Nicht schlecht ..

War es hilfreich?

Lösung

Hier gehen Sie. Ja, das ist eine hässliche böse Hack. Ja das Objekt braucht eine __dict__ Variable. Aber hey, es ist ein nettes kleines Motto!

def __init__(self):
    self.__dict__.update(locals())

Der Konstruktor kann jede Art von Argumenten entgegennehmen.

class test(object):
    def __init__(self, a, b, foo, bar=5)...

a = test(1,2,3)
dir(a)

['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'foo', 'bar', 'self']

Es wird auch selbst, aber Sie können die leicht löschen oder eigene Update-Funktion machen, die selbst ignoriert.

Andere Tipps

könnten Sie verwenden inspect.getargspec und es als Dekorateur einzukapseln. Das Nachschlagen von optionalen und Keyword-Argumente ist ein bisschen schwierig, aber das sollte es tun:

def inits_args(func):
    """Initializes object attributes by the initializer signature"""
    argspec = inspect.getargspec(func)
    argnames = argspec.args[1:]
    defaults = dict(zip(argnames[-len(argspec.defaults):], argspec.defaults))
    @functools.wraps(func)
    def __init__(self, *args, **kwargs):
        args_it = iter(args)
        for key in argnames:
            if key in kwargs:
                value = kwargs[key]
            else:
                try:
                    value = args_it.next()
                except StopIteration:
                    value = defaults[key]
            setattr(self, key, value)
        func(self, *args, **kwargs)
    return __init__

Sie können dann wie folgt verwenden:

class Foo(object):
    @inits_args
    def __init__(self, spam, eggs=4, ham=5):
        print "Foo(%r, %r, %r)" % (self.spam, self.eggs, self.ham)

Es gibt keine gute Möglichkeit, die Argumente als Liste zu bekommen, wenn sie einzeln in der Funktionssignatur festgelegt sind. Sie können sich wahrscheinlich etwas mit Hacks inspizieren oder Rahmen, aber das wird hässlicher als einfach zu buchstabieren, wie Sie getan haben.

Versuchen Sie inspect.getargspec :

In [31]: inspect.getargspec(C.__init__)

Out[31]: ArgSpec(args=['self', 'ivar1', 'ivar2', 'ivar3', 'optional'],

                 varargs=None, keywords=None, defaults=(False,))
Siehe

, wenn die neue namedtuple (neu in Python 2.6) aus der Sammlung Modul könnte für Sie arbeitet.

Sie können tun, indem sie Selbstbeobachtung der Argumente, aber der Code wird sein, länger als der Code, den Sie versuchen, zu ersetzen. Vor allem, wenn Sie kw sind Handling, die Sie haben können, zu tun.

Dieser kurze Code funktioniert in den meisten Fällen (von Unknowns Beispiel verbessert):

>>> class Foo:
...   def __init__(self, labamba, **kw):
...       params = locals().copy()
...       del params['self']
...       if 'kw' in params:
...           params.update(params['kw'])
...           del params['kw']
...       self.__dict__.update(params)

Aber es ist ein hässlicher Hack, Code machte weniger lesbar ohne besonderen Grund außer Faulheit, so tut es nicht. Und auch, wie oft Sie wirklich haben Klassen, die mehr als 5-6 init Parameter haben?

Ich mag diese Form am meisten, nicht zu lang und beide Kopie-pasteable und Unter classable:

class DynamicInitClass(object):
      __init_defargs=('x',)
      def __init__(self,*args,**attrs):
        for idx,val in enumerate(args): attrs[self.__init_defargs[idx]]=val
        for key,val in attrs.iteritems(): setattr(self,key,val)

Wie wäre es aus einer Sonderklasse ableiten? Ich denke, es ist explizite und flexibler auf diese Weise:

class InitMe:
    def __init__(self, data):
        if 'self' in data:
             data = data.copy()
             del data['self']
        self.__dict__.update(data)


class MyClassA(InitMe):
    def __init__(self, ivar1, ivar2, ivar3 = 'default value'):
        super().__init__(locals())


class MyClassB(InitMe):
    def __init__(self, foo):
        super().__init__({'xxx': foo, 'yyy': foo, 'zzz': None})
# or    super().__init__(dict(xxx=foo, yyy=foo, zzz=None))

class MyClassC(InitMe):
    def __init__(self, foo, **keywords):
        super().__init__(keywords)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top