python:采用类参数的优雅方法?

时间:2019-03-20 10:58:05

标签: python

假设我有很多类似的表情

class X:
    def __init__(self, a,b,c,d,e,f):
        self.a = a
        self.b = b
        self.c = c
        self.d = d
        self.e = e
        self.f = f

是否有一种优雅的方式来重写它?

谢谢!

4 个答案:

答案 0 :(得分:3)

您可以尝试使用命名的generic arguments

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

然后:

x = X(a=1, b=2, c=3, d=4, e=5, f=6)

但这不是一个好习惯,因为它无法控制实际传递的内容。

或者:

class X:
    def __init__(self, *args):
        for key, value in zip(['a', 'b', 'c', 'd', 'e', 'f'], args):
            setattr(self, key, value)    

然后:

x = X(1, 2, 3, 4, 5, 6)

但是,正如Zen of Python所说:

  

显式优于隐式

您的原始代码就足够了!

编辑

为了避免覆盖危险属性,请替换

setattr(self, key, value)    

使用

if not hasattr(self, key):
    setattr(self, key, value)

答案 1 :(得分:3)

class X:
    def __init__(self, a,b,c,d,e,f):
        self.a = a
        self.b = b
        self.c = c
        self.d = d
        self.e = e
        self.f = f

class X:
    def __init__(self, *args):
        arglist = ['a', 'b', 'c', 'd']
        for i in range(0, len(arglist):
            try:
                setattr(self, arglist[i], args[i])
            except IndexError:
                raise Exception('Arg {} needs to be given a value'.format(arglist[i]))

看起来不是最优雅的东西,但是列表越长越简化,您也只需修改arglist即可反映出来。不好的是,您丢失了签名(您可能做出的所有非运行时检查都丢失了,例如您的IDE会发疯

其他建议包括枚举(使用索引的更清洁方式)。

或者您可以只使用zip,然后在开始时进行检查:

class X:
    def __init__(self, *args):
        arglist = ['a', 'b', 'c', 'd']
        if len(arglist) != len(args):
           raise CustomExceptino('Too few/many arguments...')
        for keyval_tuple in zip(arglist, args):
            setattr(self, keyval_tuple[0], keyval_tuple[1])

请注意,您仍然可以添加不具有这种行为的参数:

    class X:
        def __init__(self, special_arg, *args):
            self.special_consequence = self.do_sth_with_special_arg(special_arg)
            arglist = ['a', 'b', 'c', 'd']
            if len(arglist) != len(args):
               raise CustomExceptino('Too few/many arguments...')
            for keyval_tuple in zip(arglist, args):
                setattr(self, keyval_tuple[0], keyval_tuple[1])

答案 2 :(得分:3)

从Python 3.7开始,可以使用data classes

@dataclass
class X:
    a: int
    b: str
    c: float
    # etc...

dataclass装饰器会自动生成合适的__init__方法。


正如@Lie Ryan所说,您也可以使用namedtuple

>>> X = namedtuple('X', ('a', 'b', 'c'))
>>> x = X(1, 2, 3)
>>> x
X(a=1, b=2, c=3)
>>> x.a
1

甚至可以继承添加或重载方法:

>>> class X(namedtuple('XSuper', ('a', 'b', 'c'))):
...     def __repr__(self):
...         return 'pouet'
...     
>>> x = X(1, 2, 3)
>>> x
pouet
>>> x.a
1

fountainhead的答案也是一个与版本无关的绝妙技巧。

答案 3 :(得分:3)

您可以尝试以下方法:

class X:
    def __init__(self, a,b,c,d,e,f):
        all_l = locals() # Let this be the first statement.
        for l in all_l:
            if (l != 'self'):
                self.__dict__[l] = all_l[l]

输出:

x = X(10,20,30,40,50,60)
print (x.d)

40