简体   繁体   English

Python __init__ setattr 关于参数?

[英]Python __init__ setattr on arguments?

It seems that often __init__ methods are similar to this:似乎通常__init__方法与此类似:

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

Is there someway to turn the arguments into a list (without resorting to *args or **kwargs ) and then using setattr to set the instance variables, with the name of the parameter and the argument passed?有没有办法将参数转换为列表(不诉诸*args**kwargs ),然后使用setattr设置实例变量,参数名称和参数传递? And maybe slice the list, eg you'd need to at least slice it to [1:] because you don't want self.self .也许对列表进行切片,例如,您至少需要将其切片为[1:]因为您不想要self.self

(actually I guess it would need to be a dictionary to hold the name and value) (实际上我想它需要是一个字典来保存名称和值)

like this:像这样:

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

Thanks!谢谢!

Responding to Unknown's answer, I found this to work:响应 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']))

or要么

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

Not too bad..还不错。。

Here you go.干得好。 Yes this is an ugly evil hack.是的,这是一个丑陋的邪恶黑客。 Yes the object needs a __dict__ variable.是的,对象需要一个 __dict__ 变量。 But hey, its a neat little one liner!但是,嘿,它是一个整洁的小衬里!

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

The constructor can take any type of arguments.构造函数可以接受任何类型的参数。

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

It will also include self, but you can easily delete that or make your own update function that ignores self.它还将包括 self,但您可以轻松删除它或创建自己的忽略 self 的更新函数。

You could use inspect.getargspec and encapsulate it as a decorator.您可以使用 inspect.getargspec 并将其封装为装饰器。 The lookup of optional and keyword arguments is a bit tricky, but this should do it:可选参数和关键字参数的查找有点棘手,但应该这样做:

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__

You can then use it like this:然后你可以像这样使用它:

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

There is no good way to get the arguments as a list if they are specified individually in the function signature.如果在函数签名中单独指定参数,则没有好的方法将参数作为列表获取。 You can probably do something with inspect or frame hacks, but that will be uglier than simply spelling it out as you have done.您可能可以使用检查或框架黑客来做一些事情,但这比像您所做的那样简单地拼写出来更难看。

Try inspect.getargspec :尝试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 中的新功能)是否适合您。

You can do it using introspection of the arguments, but the code is going to be longer than the code you try to replace.您可以使用自省参数来实现,但代码将比您尝试替换的代码更长。 Especially if you are handling kw, which you may have to do.特别是如果您正在处理 kw,您可能必须这样做。

This short code works in most cases (improved from Unknowns example):这个短代码适用于大多数情况(从未知示例中改进):

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

But it's an ugly hack, making code less readable for no particular reason except laziness, so don't do it.但这是一个丑陋的黑客,除了懒惰之外没有任何特别的原因使代码的可读性降低,所以不要这样做。 And also, how often do you really have classes that have more than 5-6 init parameters?而且,您真正拥有超过 5-6 个初始化参数的类的频率有多高?

I like that form the most, not too long and both copy-pasteable and sub-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)

How about deriving from a special class?从一个特殊的类派生怎么样? I think it's more explicit and more flexible this way:我认为这样更明确、更灵活

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)

If you want to declare class variables dynamically from given paramater, there is a short and clean way to do this while initializing a class:如果要从给定的参数动态声明类变量,则在初始化类时有一种简短而干净的方法可以做到这一点:

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