2011-02-19 10 views
7

¿Hay alguna manera de enlazar automáticamente a self (algunos de) los argumentos del método __init__?Decorador de Python para enlace automático __init__ argumentos

quiero decir algo como:

class Person: 
    @lazy_init 
    def __init__(self, name, age, address): 
     ... 

... en lugar de:

class Person: 
    def __init__(self, name, age, address): 
     self.name = name 
     self.age = age 
     self.address = address 
     ... 

Me pregunto si hay algo similar que las personas ya usan en estos casos. ¿O hay alguna razón por la que se supone que no debo hacerlo de esta manera en primer lugar?

Respuesta

4

Es definitivamente posible, he aquí una aplicación un tanto ingenua:

def lazy_init(init): 
    import inspect 
    arg_names = inspect.getargspec(init)[0] 

    def new_init(self, *args): 
     for name, value in zip(arg_names[1:], args): 
      setattr(self, name, value) 
     init(self, *args) 

    return new_init 

class Person: 
    @lazy_init 
    def __init__(self, name, age): 
     pass 

p = Person("Derp", 13) 
print p.name, p.age 

Una vez que empieza a tener algo además de los atributos que se asignan a propiedades, vas a tener problemas sin embargo. Necesitarás al menos alguna forma de especificar qué argumentos para inicializar como propiedades ... en ese punto se volverá más complicado de lo que vale.

+0

Gracias. Me doy cuenta de que si el método '__init__' es sofisticado, no valdría la pena, pero los simples están tan extendidos que creo que sería bueno tener algo así a mano. –

0

Aquí va, en la forma más simple:

def lazy_init(*param_names): 
    def ret(old_init): 
    def __init__(self, *args, **kwargs): 
     if len(args) > len(param_names): 
     raise TypeError("Too many arguments") 
     for k in kwargs: 
     if k not in param_names: 
      raise TypeError("Arg %r unexpected" % k) 
     for par, arg in zip(param_names, args): 
     setattr(self, par, arg) 
     for par, arg in kwargs.items(): 
     setattr(self, par, arg) 
     old_init(*args, **kwargs) 
    return __init__ 
    # 
    return ret 


class Q(object): 
    @lazy_init("a", "b") 
    def __init__(self, *args, **kwargs): 
    print "Original init" 

>>> q = Q(1, 2) 
Original init 
>>> q.a, q.b 
(1, 2) 

considere hacer un decorador de clase para cubrir __str__ también.

0

initify.py creado por mí :) hace exactamente lo que cabría esperar.

class Animal: 
    @init_args(exclude=["name"]) 
    def __init__(self, name): 
     pass 

o con valores predeterminados:

class Animal: 
    @init_args 
    def __init__(self, name="Default name"): 
     pass 

o incluso excluyendo la herencia:

class Dog(Animal): 
    @init_args(exclude=["name"]) 
    def __init__(self, species): 
     pass 

https://github.com/prankymat/initify.py

Cuestiones relacionadas