在我的 Python 项目中,我大量使用 Mixins 作为设计模式,并且我想继续这样做。但是,我在最后一堂课中遇到了
__init__
方法签名的问题。由于我通过 **kwargs
传递参数,因此生成的签名对于内省、文档或类型检查没有帮助。下面举个例子来说明这个问题:
class Base:
def __init__(self, arg1):
self.arg1 = arg1
class ParamMixin1:
def __init__(self, arg2, **kwargs):
super().__init__(**kwargs)
self.arg2 = arg2
class ParamMixin2:
def __init__(self, arg3, **kwargs):
super().__init__(**kwargs)
self.arg3 = arg3
class NonParamMixin:
def __init__(self, **kwargs):
super().__init__(**kwargs)
class Derived(NonParamMixin, ParamMixin1, ParamMixin2, Base):
pass
d = Derived(arg1=1, arg2=2, arg3=3)
from inspect import signature
print(signature(Derived.__init__))
打印:
(self, **kwargs)
签名不是很有帮助,因为所有参数都隐藏在
**kwargs
下。我可以从技术上重写像这样的 __init__
方法来公开完整的签名:
class Base:
def __init__(self, arg1):
self.arg1 = arg1
class ParamMixin1:
def __init__(self, arg2, arg1):
super().__init__(arg1)
self.arg2 = arg2
class ParamMixin2:
def __init__(self, arg3, arg2, arg1):
super().__init__(arg2, arg1)
self.arg3 = arg3
class NonParamMixin:
def __init__(self, arg3, arg2, arg1):
super().__init__(arg3, arg2, arg1)
class Derived(NonParamMixin, ParamMixin1, ParamMixin2, Base):
pass
from inspect import signature
print(signature(Derived.__init__))
这是可行的,并且签名提供了更多信息,但它引入了很多样板文件并且需要参数的正确顺序,这有时并不重要,具体取决于所使用的 mixin。此外,有时只使用 mixins 的一个子集。
我尝试创建一个元类来动态覆盖
__init__
签名,但它变得非常混乱,而且我无法让它可靠地工作。
但是,无法访问正确的
__init__
签名感觉是违反直觉的。如果没有它,我需要手动跟踪所有 mixin 及其所需的参数,这似乎不切实际。当然,有更好的方法来管理这个问题吗?
任何实现更清洁、更易于维护的解决方案的建议或替代方法也将不胜感激!
from dataclasses import dataclass
from inspect import signature
@dataclass(kw_only=True)
class Base:
arg1: int
@dataclass(kw_only=True)
class ParamMixin1:
arg2: int
@dataclass(kw_only=True)
class ParamMixin2:
arg3: int
@dataclass
class NonParamMixin:
pass
@dataclass
class Derived(NonParamMixin, ParamMixin1, ParamMixin2, Base):
pass
d = Derived(arg1=1, arg2=2, arg3=3)
# d = Derived(1, 2, 3) # raises an error because of kw_only=True
print(signature(Derived.__init__))
# (self, *, arg1: int, arg3: int, arg2: int) -> None
# * means that all the arguments after * are keyword-only arguments
# This way you don't have to worry about order