基本思想是编写
__init__为您生成该方法的代码,其中使用显式指定的所有参数,而不是通过
*args和/或
**kwargs,并且甚至无需在所有这些
self.arg1= arg1行中重复进行操作。
并且,理想情况下,它可以使添加PyCharm可用于弹出提示和/或静态类型检查的类型注释变得容易。1个
而且,当您使用它时,为什么不构建一个
__repr__显示相同值的?甚至可能还有
__eq__,和
__hash__,以及字典比较操作符,以及往返于的转换,
dict其键与每个JSON持久性的属性相匹配,并且…
或者,甚至更好的是,使用可以为您解决这些问题的库。
Python
3.7附带了这样的库
dataclasses。或者,您可以使用第三方库(例如)
attrs,该库可与Python
3.4和2.7(但有一定限制)一起使用。或者,对于简单的情况(对象是不可变的,并且您希望它们按照指定的顺序像其属性的元组一样工作),可以使用
namedtuple,其适用于3.0和2.6。
不幸的是,
dataclasses它不适用于您的用例。如果您只是这样写:
from dataclasses import dataclass@dataclassclass Parent: arg1: str opt_arg1: str = 'opt_arg1_default_val' opt_arg2: str = 'opt_arg2_default_val' opt_arg3: str = 'opt_arg3_default_val' opt_arg4: str = 'opt_arg4_default_val'@dataclassclass Child(Parent): arg2: str
…你会得到一个错误,因为它试图强制参数将
arg2默认值参数后
opt_arg1通过
opt_arg4。
dataclasses没有任何方法可以对参数(
Child(arg1, arg2,opt_arg1=…)进行重新排序,也不能使其强制为仅关键字的参数(
Child(*, arg1, opt_arg1=…,arg2))。
attrs没有开箱即用的功能,但是您可以添加它。
因此,它并不像您希望的那么琐碎,但却是可行的。
但是,如果您想自己编写此代码,您将如何
__init__动态创建函数?
最简单的选择是
exec。
您可能听说过这
exec很危险。但这只是危险,如果您要传递来自用户的值。在这里,您只传递来自您自己的源代码的值。
它仍然很丑陋,但有时仍然是最好的答案。标准库
namedtuple曾经是一个巨大的
exec模板。,甚至当前版本都
exec用于大多数方法,确实如此
dataclasses。
另外,请注意,所有这些模块都将字段集存储在私有类属性中的某个位置,因此子类可以轻松读取父类的字段。如果您不这样做,则可以使用该
inspect模块获取
Signature基类(或用于多重继承的基类)的初始化程序,然后从那里开始。但是,
base._fields显然使用起来要简单得多(并允许存储通常不在签名中包含的额外元数据)。
这里是一个死的简单实现不处理大部分的功能
attrs或
dataclasses,但不会为了所有自选前所有必须的参数。
def makeinit(cls): fields = () optfields = {} for base in cls.mro(): fields = getattr(base, '_fields', ()) + fields optfields = {**getattr(base, '_optfields', {}), **optfields} optparams = [f"{name} = {val!r}" for name, val in optfields.items()] paramstr = ', '.join(['self', *fields, *optparams]) assignstr = "n ".join(f"self.{name} = {name}" for name in [*fields, *optfields]) exec(f'def __init__({paramstr}):n {assignstr}ncls.__init__ = __init__') return cls@makeinitclass Parent: _fields = ('arg1',) _optfields = {'opt_arg1': 'opt_arg1_default_val', 'opt_arg2': 'opt_arg2_default_val', 'opt_arg3': 'opt_arg3_default_val', 'opt_arg4': 'opt_arg4_default_val'}@makeinitclass Child(Parent): _fields = ('arg2',)现在,你已经得到了完全
__init__你想上的方法
Parent和
Child,完全可检查2(含
help),而不必重复自己。
1.我不使用PyCharm,但是我知道在3.7发行之前,他们的开发人员已经参与了讨论,
@dataclass并且已经在为IDE添加对它的显式支持,因此它甚至不必评估类定义以获取所有这些信息。我不知道它是否在当前版本中可用,但是如果没有,我认为它将可用。同时,
@dataclass已经可以通过IPython自动完成功能,emacs
flycheck等对我有效,这对我来说已经足够了。:)
2.…至少在运行时。PyCharm可能无法静态地很好地解决问题,无法完成弹出窗口。



