2009-09-14 1 views
5

кажется, что часто __init__ методы похожи на это:Python __init__ setattr по аргументам?

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

Есть ли каким-то образом, чтобы включить аргументы в список (не прибегая к *args или **kwargs), а затем с помощью setattr установить переменные экземпляра, с имя параметра и переданный аргумент? И, возможно, нарежьте список, например. вам нужно хотя бы нарезать его на [1:], потому что вы не хотите self.self.

(на самом деле я думаю, что это необходимо будет словарь держать имя и значение)

так:

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

Спасибо!

В ответ на ответ не указан, я нашел, что это работает:

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

или

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

Не так уж плохо ..

+1

повторов Http://stackoverflow.com/questions/1389180/python-automatically-initialize-instance-variables – SilentGhost

+1

см. также: http://stackoverflow.com/questions/739625/setattr-with-kwargs-pythonic-or-not – Imran

ответ

7

Здесь вы идете. Да, это уродливый злой хак. Да, объект нуждается в переменной __dict__. Но эй, его аккуратный маленький лайнер!

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

Конструктор может принимать любые аргументы.

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

Он также будет включать в себя self, но вы можете легко удалить это или сделать свою собственную функцию обновления, которая игнорирует себя.

+0

Это не делает то, что хотел OP: он вообще не принимает аргументов! –

+1

@Ned, он делает ... Вы можете указать любой тип аргумента, который вы хотите. – Unknown

+2

Это установит все локальные переменные в качестве атрибутов, в частности «я», что является абсурдным. :) Вы можете, конечно, сначала фильтровать «я» из местных жителей(), но потом он становится менее аккуратным. –

4

Там нет хороший способ, чтобы получить аргументы в качестве если они указаны отдельно в сигнатуре функции. Возможно, вы можете что-то сделать с проверкой или фальшивыми хаками, но это будет уродливее, чем просто написание его, как вы это делали.

+0

Он не может делаться даже при просмотре функций или объектов кода. В то время как вы могли бы сделать что-то неприятное, как будто первый аргумент 'co_argcount'' co_varnames' - это аргументы, это не будет истинным перед распаковкой последовательности или * args/** kwargs. – bobince

+0

Нед, мой метод работает для любой сигнатуры метода, не прибегая к проверке или фрейму. – Unknown

2

Посмотрите, может ли новый вами namedtuple (новый в Python 2.6) из модуля коллекций работать на вас.

3

Попробуйте inspect.getargspec:

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

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

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

Вы можете использовать inspect.getargspec и инкапсулировать его в качестве декоратора. Поиск необязательных и именованных аргументов немного сложнее, но это должно сделать это:

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__ 

Вы можете использовать его как это:

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

Вы можете сделать это с помощью интроспекции из аргументов, но код будет длиннее кода, который вы пытаетесь заменить. Особенно, если вы занимаетесь kw, что вам, возможно, придется делать.

Этот короткий код работает в большинстве случаев (например улучшился с Неизвестными):

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

Но это уродливое рубить, что делает код менее читаемым без особой причины, кроме лени, поэтому не делайте этого. А также, как часто у вас есть действительно есть классы, которые имеют более 5-6 параметров init?

0

Как насчет того, чтобы получить специальный класс? Я думаю, что это более четко и более гибкий таким образом:

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

Мне нравится, что сформировать большинство, не слишком долго, и как копировать-pasteable и суб-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) 

 Смежные вопросы

  • Нет связанных вопросов^_^