Python _; init _; setattr的参数?

Python _; init _; setattr的参数?,python,list,parameters,initialization,setattr,Python,List,Parameters,Initialization,Setattr,似乎通常\uuuu init\uuuu方法与此类似: def __init__(self, ivar1, ivar2, ivar3): self.ivar1 = ivar1 self.ivar2 = ivar2 self.ivar3 = ivar3 是否有办法将参数转换成一个列表(无需求助于*args或**kwargs),然后使用setattr设置实例变量,并传递参数名称和参数?并且可能对列表进行切片,例如,您至少需要将其切片为[1://code>,因为您不需要self

似乎通常
\uuuu init\uuuu
方法与此类似:

def __init__(self, ivar1, ivar2, ivar3):
    self.ivar1 = ivar1
    self.ivar2 = ivar2
    self.ivar3 = ivar3
是否有办法将参数转换成一个列表(无需求助于
*args
**kwargs
),然后使用
setattr
设置实例变量,并传递参数名称和参数?并且可能对列表进行切片,例如,您至少需要将其切片为
[1://code>,因为您不需要
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 Foo(object):
    @inits_args
    def __init__(self, spam, eggs=4, ham=5):
        print "Foo(%r, %r, %r)" % (self.spam, self.eggs, self.ham)
谢谢

在回答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']))


还不错。

如果在函数签名中单独指定参数,则没有好的方法将其作为列表获取。您可能可以使用inspect或frame hacks进行一些操作,但这比简单地按照您所做的那样进行拼写要难看得多。

看看collections模块中的新名称(Python 2.6中的新名称)是否适合您。

开始吧。是的,这是一个丑陋的邪恶黑客。是的,对象需要一个_udict__;变量。但是,嘿,这是一个整洁的小班轮

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并将其封装为decorator。可选参数和关键字参数的查找有点棘手,但这应该可以做到:

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__
然后您可以这样使用它:

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 Foo(object):
    @inits_args
    def __init__(self, spam, eggs=4, ham=5):
        print "Foo(%r, %r, %r)" % (self.spam, self.eggs, self.ham)

您可以使用自省参数来完成,但是代码将比您尝试替换的代码更长。尤其是当你处理千瓦时,你可能不得不这样做

此短代码在大多数情况下都有效(从未知示例改进):


但这是一个丑陋的黑客行为,除了懒惰之外,没有任何特殊原因使代码可读性降低,所以不要这样做。另外,您真正拥有超过5-6个init参数的类的频率是多少?

从特殊类派生如何?我认为这样做更明确、更灵活:

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

即使通过查看函数或代码对象也无法完成。虽然您可能会做一些令人讨厌的事情,比如假设
co_varnames
的第一个
co_argcount
是参数,但在序列解包或*args/**kwargs.Ned面前,这是不正确的,我的方法适用于任何方法签名,而不需要进行检查或框架破解。这并不是OP想要的:它根本不需要参数@奈德,是的。。。您可以指定任何类型的参数。这会将所有局部变量设置为属性,特别是“self”,这有点荒谬。:)当然,你可以先从locals()中过滤出“self”,但它已经变得不那么整洁了。@Lennart,这是你想要的行为。除了self,它很容易被删除,正如你对这个答案的理解所证明的。啊,我明白了:你的第一个例子简单地说,_init__(self)。dupe也看到:
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'