从默认参数设置类属性

时间:2015-07-27 09:51:00

标签: python

我想自动将默认参数设置为类属性。 例如,我有(有更多的参数,比如十几个或两个):

class Foo:
    def __init__(self,a=1,b=2,c=3,...):
        self.a = a
        self.b = b
        self.c = c
        ...

我希望自动定义属性,而不必在self.x = x正文中一直重写__init__

我可以使用类似的东西:

class Foo:
    def __init__(self, **kwargs):
        for attr, value in kwargs.items():
            setattr(self,attr,value)

但现在我不能给它们默认值。 我想要的是一些函数,它给我一个带有默认值的参数字典:

class Foo:
    def __init__(self,a=1,b=2,c=3,...,**kwargs):
        defargs = somefunction()

defargs{'a':1,'b':2,'c':3,...}(但不包含kwargs)。

我设法做的最近的事情是:

class Foo:
    def __init__(self,a=1,b=2,c=3,...,**kwargs):
        defargs=locals()
        defargs.pop('self')
        defargs.pop('kwargs')
        for attr, value in defargs.items():
            setattr(self,attr,value)

但我不知道此代码中是否存在一些潜在的不安全行为。

3 个答案:

答案 0 :(得分:3)

您可以手动将默认值定义为dict:

<style type="text/css">
/* 
Generic Styling, for Desktops/Laptops 
*/
.table-hover { 
  width: 100%; 
  border-collapse: collapse; 
}
/* Zebra striping */
tr:nth-of-type(odd) { 
  background: #eee; 
}
th { 
  background: #333; 
  color: white; 
  font-weight: bold; 
}
td, th { 
  padding: 6px; 
  border: 1px solid #ccc; 
  text-align: left; 
}

tr:hover {
  background-color: lightyellow;
}

</style>

答案 1 :(得分:3)

在Python 3.3+中,可以使用inspect.signature轻松完成:

import inspect


def auto_assign(func):
    signature = inspect.signature(func)

    def wrapper(*args, **kwargs):
        instance = args[0]
        bind = signature.bind(*args, **kwargs)
        for param in signature.parameters.values():
            if param.name != 'self':
                if param.name in bind.arguments:
                    setattr(instance, param.name, bind.arguments[param.name])
                if param.name not in bind.arguments and param.default is not param.empty:
                    setattr(instance, param.name, param.default)
        return func(*args, **kwargs)

    wrapper.__signature__ = signature # Restore the signature

    return wrapper


class Foo:
    @auto_assign
    def __init__(self, foo, bar, a=1, b=2, c=3):
        pass

f = Foo(10, 20)
g = Foo(100, 200, a=999)

print(f.__dict__)
print(g.__dict__)
print(inspect.getargspec(Foo.__init__))

输出:

{'bar': 20, 'b': 2, 'foo': 10, 'c': 3, 'a': 1}
{'bar': 200, 'b': 2, 'foo': 100, 'c': 3, 'a': 999}
ArgSpec(args=['self', 'foo', 'bar', 'a', 'b', 'c'], varargs=None, keywords=None, defaults=(1, 2, 3))

答案 2 :(得分:1)

您始终可以设置实际的类属性(您指的是实例属性)来保存默认值,并明确地获取它们:

class Foo:

    # default attribute values
    a = 1 
    ...

    def __init__(self, **kwargs):
        setattr(self, 'a', kwargs.get('a', getattr(self, 'a')))
        ...

或者只是让它们正常访问(不推荐表示可变属性):

class Foo:

    # default attribute values
    a = 1 
    ...

    def __init__(self, **kwargs):
        if 'a' in kwargs:
            setattr(self, 'a', kwargs['a'])
        ...

无论哪种方式,Foo().a都会为您提供1Foo(a=2).a会为您提供2,现在您可以轻松地重构为('a', ...)以上的循环相关属性的名称。