如何从 init 参数正确设置 Python class 属性
How to properly set Python class attributes from init arguments
作为一名 Python 程序员,我经常声明 class 类似于
class Foo:
def __init__(self, attr1, attr2, attr3, attr4, attr5, attr6, attr7, attr8, attr9):
self.attr1 = attr1
self.attr2 = attr2
...
self.attr9 = attr9
# init your class
问题是我一遍又一遍地这样做,感觉效率很低。在 C++ 中,执行此操作的方法是
class Foo {
public:
Foo(int, int, int, int, int);
private:
int attr1, attr2, attr3, attr4, attr5;
};
Foo::Foo(int attr1, int attr2, int attr3, int attr4, int attr5) :
attr1(attr1), attr2(attr2), attr3(attr3), attr4(attr4), attr5(attr5) {
// init your class
}
我觉得这样效率更高一些。我的问题是:是否有一种标准方法可以避免将每个参数的参数都归因于 class?我可以想办法编程,例如
def attribute_setter(*arg_names):
def wrapper(func):
def setter_init(self, *args, **kwargs):
for i, name in enumerate(arg_names):
if i < len(args):
setattr(self, name, args[i])
elif name in kwargs:
setattr(self, name, kwargs[name])
func(self, *args, **kwargs)
return setter_init
return wrapper
class Foo:
@attribute_setter('attr1', 'attr2', 'attr3', 'attr4', 'attr5', 'attr6', 'attr7', 'attr8', 'attr9')
def __init__(self, *args, **kwargs):
# init your class
pass
产生
>>> foo = Foo(1, 2, 3, 4, 5, attr6=6, attr7=7, attr8=8, attr9=9)
>>> foo.attr1
1
>>> foo.attr9
9
通过更多的错误处理,这个装饰器可能可以安全使用,但我担心的是代码的可读性,并确保我没有违反任何良好实践原则。
这正是 dataclasses
模块的用途。你这样使用它:
from dataclasses import dataclass
@dataclass
class Foo:
attr1: str
attr2: int
attr3: bool
# ...etc...
这为您提供了一个带有隐式 __init__
方法的 class
为您处理所有参数设置。你也会得到像
有用的 __repr__
和 __str__
预定义:
>>> myvar = Foo(attr1="somevalue", attr2=42, attr3=False)
>>> myvar
Foo(attr1='somevalue', attr2=42, attr3=False)
>>> print(myvar)
Foo(attr1='somevalue', attr2=42, attr3=False)
作为一名 Python 程序员,我经常声明 class 类似于
class Foo:
def __init__(self, attr1, attr2, attr3, attr4, attr5, attr6, attr7, attr8, attr9):
self.attr1 = attr1
self.attr2 = attr2
...
self.attr9 = attr9
# init your class
问题是我一遍又一遍地这样做,感觉效率很低。在 C++ 中,执行此操作的方法是
class Foo {
public:
Foo(int, int, int, int, int);
private:
int attr1, attr2, attr3, attr4, attr5;
};
Foo::Foo(int attr1, int attr2, int attr3, int attr4, int attr5) :
attr1(attr1), attr2(attr2), attr3(attr3), attr4(attr4), attr5(attr5) {
// init your class
}
我觉得这样效率更高一些。我的问题是:是否有一种标准方法可以避免将每个参数的参数都归因于 class?我可以想办法编程,例如
def attribute_setter(*arg_names):
def wrapper(func):
def setter_init(self, *args, **kwargs):
for i, name in enumerate(arg_names):
if i < len(args):
setattr(self, name, args[i])
elif name in kwargs:
setattr(self, name, kwargs[name])
func(self, *args, **kwargs)
return setter_init
return wrapper
class Foo:
@attribute_setter('attr1', 'attr2', 'attr3', 'attr4', 'attr5', 'attr6', 'attr7', 'attr8', 'attr9')
def __init__(self, *args, **kwargs):
# init your class
pass
产生
>>> foo = Foo(1, 2, 3, 4, 5, attr6=6, attr7=7, attr8=8, attr9=9)
>>> foo.attr1
1
>>> foo.attr9
9
通过更多的错误处理,这个装饰器可能可以安全使用,但我担心的是代码的可读性,并确保我没有违反任何良好实践原则。
这正是 dataclasses
模块的用途。你这样使用它:
from dataclasses import dataclass
@dataclass
class Foo:
attr1: str
attr2: int
attr3: bool
# ...etc...
这为您提供了一个带有隐式 __init__
方法的 class
为您处理所有参数设置。你也会得到像
有用的 __repr__
和 __str__
预定义:
>>> myvar = Foo(attr1="somevalue", attr2=42, attr3=False)
>>> myvar
Foo(attr1='somevalue', attr2=42, attr3=False)
>>> print(myvar)
Foo(attr1='somevalue', attr2=42, attr3=False)