Python 将参数传递给super()。_init_uuu,同时将其名称保留在签名中的优雅方式? A类: 定义初始化(self,x1,x2,x3,x4): 通过 ... B(A)类: 定义初始化(self,x1,x2,x3,x4,y1,y2): super().uuu init_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuux1x2x3x4)#如何替换此? ...

Python 将参数传递给super()。_init_uuu,同时将其名称保留在签名中的优雅方式? A类: 定义初始化(self,x1,x2,x3,x4): 通过 ... B(A)类: 定义初始化(self,x1,x2,x3,x4,y1,y2): super().uuu init_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuux1x2x3x4)#如何替换此? ...,python,Python,我不喜欢,因为它隐藏了真实的签名 一种解决方案可以是: 来自检查导入签名 B(A)类: 定义初始化(self,x1,x2,x3,x4,y1,y2): sig=签名(super()。\uuuu init\uuuu) params={k:v表示k,v表示局部变量().items(),如果k表示sig.parameters} 超级() ... 但这很麻烦,也有自己的问题。还有什么比这更优雅的吗 编辑:这个问题的动机是干燥原则。扩展我的评论: 听起来像是x1、x2、x3、x4在逻辑上被分组,因为您可以

我不喜欢,因为它隐藏了真实的签名

一种解决方案可以是:

来自检查导入签名
B(A)类:
定义初始化(self,x1,x2,x3,x4,y1,y2):
sig=签名(super()。\uuuu init\uuuu)
params={k:v表示k,v表示局部变量().items(),如果k表示sig.parameters}
超级()
...
但这很麻烦,也有自己的问题。还有什么比这更优雅的吗


编辑:这个问题的动机是干燥原则。

扩展我的评论:

听起来像是
x1、x2、x3、x4
在逻辑上被分组,因为您可以看到它们的名称在整个类层次结构中重复在一起。您可以使用
元组来消除重复。更好的解决方案是,如果逻辑分组是在初始化时建立的,并且在初始化后不应更改,则最好是只读的。这两种解决方案都支持异构类型

from dataclasses import dataclass

@dataclass(frozen=True)
class X:
    x1: ...
    x2: ...
    x3: ...
    x4: ...
请注意,这里不需要使用
@dataclass
,实际上,任何使用
\uuuu init\uuuu
方法来聚合此数据并将其分配给
self
属性的类都可以工作。但是
@dataclass
在这里提供了一些漂亮的功能,请参见链接和注释

如果
x1
的类型
x4
是同质的,您不需要特别强制执行其中的4个
x
s,如果您需要索引功能,您可以使用
列表
,否则
set
(甚至
frozenset
强制执行仅在初始化时执行此分组)


关键是,有一个聪明的解决方案可以满足您的需求,但在这里使用结构来聚合数据自然可以避免重复。此结构将使用一个名称,您只需将此参数传递给
super()。\uuuu init\uuuu

我理解,通常应该避免这个问题-最好按照使用
数据类
,或者按照注释中的建议重新编写参数

但是为了这项运动,为了有一天这项运动真的对某人有用,我提出了以下解决方案:

导入检查
从functools导入包装
def调用_base_init(init):
@包装(初始化)
def包装(*args,**kwargs):
sig_init=检查签名(init)
bargs=sig_init.bind(*args,**kwargs)
对于参数[0]中的cls。\u类\u类\u基\u类:
sig=检查签名(cls.\uuuuu init\uuuuuuu)
params={k:v代表k,v在bargs.arguments.items()中如果k在sig.parameters中如果k!=“self”}
如果len(参数)==len(信号参数)-1:
cls.\uuuu init\uuuu(参数[0],**参数)
打破
其他:
assert False,f“在{args[0]的基类中找不到适当的签名。\uuuuuu class\uuuuuuuu.\uuuuuuuuu name\uuuuuuuuu}”
初始(*args,**kwargs)
返回包装器
然后在派生类的
\uuuu init\uuuu
上使用装饰器:

A类:
定义初始化(self,x1,x2,x3,x4):
打印(x1、x2、x3、x4)
B(A)类:
@调用_base_init
定义初始化(self,x1,x2,x3,x4,y1,y2):
打印(y1,y2)
B(11、12、13、14、21、22)
产出:

11 12 13 14
21 22

>

是的,只需写出来。考虑制作<代码> x1、x2、x3、x4< /代码> A<代码> @ DATACLAS< <代码>。然后您只需将这个
@dataclass
按名称传递给
super()。\uuuu init\uuu
。是的,有时您会牺牲DRY,但牺牲DRY比这种怪物更可取:
参数={k:v代表k,v代表局部变量().items()如果k代表sig.parameters};super()。所以现在你必须想,“嘿,不能使用局部变量,否则它会破坏我的
super
调用”。那太疯狂了。你不妨重复你自己。如果有一个更好的首字母缩略词“不要不必要地重复你自己”,那就太好了;DRY可能会走极端。好吧,但是你看,谈论
@dataclass
有点像是在转移注意力。这对于一个普通类来说是很好的,这就是
@datclass
生成的类,不管怎样,它只是删除了样板文件。但是,是的,当争论失控时,这通常是一种方式。@juanpa.arrivillaga是的,你是对的,任何类在这里都可以。但是
@dataclass
确实提供了一些漂亮的特性,比如只读属性和生成的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。我将进行编辑以澄清。是的,尽管我再次指出,
@dataclass
只是删除了样板文件,但您可以正常地完成所有这些。