Question

Il semble que les méthodes __ init __ soient souvent similaires à ceci:

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

Existe-t-il un moyen de transformer les arguments en liste (sans recourir à * args ou ** kwargs ), puis en utilisant setattr pour définir les variables d'instance, avec le nom du paramètre et l'argument passé? Et peut-être couper la liste, par exemple vous devez au moins le découper en [1:] car vous ne voulez pas self.self .

(en fait, je suppose qu'il faudrait un dictionnaire pour contenir le nom et la valeur)

comme ceci:

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

Merci!

En réponse à la réponse de l'inconnu, j'ai constaté que cela fonctionnait:

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

ou

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

Pas trop mal ..

Était-ce utile?

La solution

Ici vous allez. Oui, c'est un vilain bidouillage. Oui, l'objet a besoin d'une variable __dict__. Mais bon, c’est un beau petit manchon!

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

Le constructeur peut accepter n'importe quel type d'argument.

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']

Cela inclura également self, mais vous pouvez facilement le supprimer ou créer votre propre fonction de mise à jour qui ignore self.

Autres conseils

Vous pouvez utiliser inspect.getargspec et l’encapsuler en tant que décorateur. La recherche d’arguments optionnels et de mots clés est un peu délicate, mais vous devriez le faire:

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__

Vous pouvez ensuite l'utiliser comme ceci:

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

Il n’existe aucun moyen efficace d’obtenir les arguments sous forme de liste s’ils sont spécifiés individuellement dans la signature de la fonction. Vous pouvez probablement faire quelque chose avec des hacks à inspecter ou à encadrer, mais cela sera plus laid que de simplement l'épeler comme vous l'avez fait.

Essayez inspect.getargspec :

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

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

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

Vérifiez si le nouveau nom nommé (nouveau dans Python 2.6) du module collections peut fonctionner pour vous.

Vous pouvez le faire en utilisant l'introspection des arguments, mais le code sera plus long que le code que vous essayez de remplacer. Surtout si vous manipulez kw, ce que vous devrez peut-être faire.

Ce code de fonction fonctionne dans la plupart des cas (amélioré à partir de l'exemple Unknowns):

>>> 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)

Mais c’est un vilain bidouillage qui rend le code moins lisible sans raison particulière, sauf la paresse, alors ne le faites pas. Et aussi, combien de fois avez-vous vraiment des classes qui ont plus de 5 à 6 paramètres init?

J'aime la forme la plus longue, pas trop longue, à la fois copier-coller et sous-classer:

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)

Pourquoi ne pas dériver d'une classe spéciale? Je pense que c'est plus explicite et plus flexible de cette façon:

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)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top