簡體   English   中英

Python __init__ setattr 關於參數?

[英]Python __init__ setattr on arguments?

似乎通常__init__方法與此類似:

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)

謝謝!

響應 Unknown 的回答,我發現這有效:

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

還不錯。。

干得好。 是的,這是一個丑陋的邪惡黑客。 是的,對象需要一個 __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,但您可以輕松刪除它或創建自己的忽略 self 的更新函數。

您可以使用 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)

如果在函數簽名中單獨指定參數,則沒有好的方法將參數作為列表獲取。 您可能可以使用檢查或框架黑客來做一些事情,但這比像您所做的那樣簡單地拼寫出來更難看。

嘗試inspect.getargspec

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

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

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

看看 collections 模塊中的新命名元組(Python 2.6 中的新功能)是否適合您。

您可以使用自省參數來實現,但代碼將比您嘗試替換的代碼更長。 特別是如果您正在處理 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 個初始化參數的類的頻率有多高?

我最喜歡這種形式,不要太長,並且可以復制粘貼和子分類:

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)

從一個特殊的類派生怎么樣? 我認為這樣更明確、更靈活

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)

如果要從給定的參數動態聲明類變量,則在初始化類時有一種簡短而干凈的方法可以做到這一點:

class Foo():

    def __init__(self, **content):
        if isinstance(content, dict):
            self.hello = 'world' # normal declaration instance variable
            for key, value in content.items():
                self.__setattr__(key, value)

    test = "test" # class variable


>>> content = {'foo':'bar'}
>>> instance = Foo(**content)
>>> instance.foo 
>>> 'bar'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM