![](/img/trans.png)
[英]When calling super().__init__ how can I tell if the super init is object.__init__ in python3?
[英]How can I generically pass params to super().__init__()?
通常,子类__init__
只会将其所需的所有参数传递给super().__init__
,然后还要执行其他操作。 有没有一种干净的方法可以执行此操作,而无需复制代码中的参数? 在下面的示例中, a,b,c,d,e
出现3次。 我想要一些“魔术”来解决这个问题。 有args
和kwargs
吗?
class A:
def __init__(self,a,b,c,d,e):
# ... use params here ...
pass
class B(A):
def __init__(self,a,b,c,d,e,f,g,h):
super().__init__(a,b,c,d,e)
# do something with params f,g,h
pass
这是使用python 3.7新增的dataclasses模块最容易实现的。 它仅对相对简单的类有帮助。 正如注释中指出的那样,数据类并非没有局限性。 如果只使用简单的记录风格的类,那么这是减少样板代码的好方法。 对于任何更复杂的事情,显式胜于隐式。 也就是说,写出自己的__init__
并执行所需的操作。 例如,在将参数传递给super之前先对其进行更改,或者添加不具有默认值的新参数(当super类确实具有默认参数时)。
from dataclasses import dataclass, field, InitVar, fields
@dataclass
class X:
a: int
# the dataclass decorator creates the following __init__ method
# def __init__(self, a):
# self.a = a
@dataclass
class Y(X):
b: int=2
c: int=field(init=False) # c is a computed value and not passed to __init__
op: InitVar[str]="add" # op is present in __init__, but not stored
# (it is still a class variable though, with value "add")
# dataclass decorator creates an __init__method taking a, b, and op. But
# it only stores b and passes a to super().__init__
def __post_init__(self, op):
# do some processing once fields have been initialised
if op == "add":
self.c = self.a + self.b
elif op == "sub":
self.c = self.a - self.b
else:
raise ValueError('invalid op')
x = X(1) # X instance with only a value
assert x.a == 1
y = Y(10, 20) # creating Y instance, passing both `a` and `b` (passing `c`
# would be an error)
assert y.a == 10 and y.b == 20 and y.c == 30
y1 = Y(100, op="sub") # creating Y instance with just field `a` and non-field `op`
assert y1.a == 100 and y1.b == 2 and y1.c == 98
是的,您可以使用kwargs。 您可以使用** kwargs来让函数接受任意数量的关键字参数(“ kwargs”表示“关键字参数”)。 在这里使用:
def __init__(self, *args, **kwargs)
当创建一个类的实例时,我们需要解开kwarg,因此是** kwargs。
b_instance = B(**test_kwargs)
根据您的示例,完整代码为:
test_kwargs = {
'a': 1,
'b': 2,
'c': 3,
'd': 4,
'e': 5,
'f': 6,
'g': 7,
}
class A():
def __init__(self, *args, **kwargs):
self.a = kwargs.get('a')
self.b = kwargs.get('b')
self.c = kwargs.get('c')
self.d = kwargs.get('d')
self.e = kwargs.get('e')
class B(A):
def __init__(self, *args, **kwargs):
# super(A, self).__init__(*args, **kwargs) resolves
# to object base class which takes no parameter
# You will get this error
# TypeError: object.__init__() takes no parameters
super(B, self).__init__(*args, **kwargs)
self.f = kwargs.get('f')
self.g = kwargs.get('g')
def print_all_instance_vars(self):
# self.__dict__.items() =
# dict_items(
# [('a', 1), ('b', 2), ('c', 3),
# ('d', 4), ('e', 5), ('f', 6),
# ('g', 7)])
for key, value in self.__dict__.items():
print("{}:{}".format(key, value))
b_instance = B(**test_kwargs)
b_instance.print_all_instance_var()
# a:1
# b:2
# c:3
# d:4
# e:5
# f:6
# g:7
在类B中,您只需分配其自己的实例变量,因为B继承自A。因此,B将所有A的实例变量作为其默认值。
但是,如果您必须编写此类丑陋的代码,则可能需要重新考虑设计决策。 实例变量过多会在将来造成混乱。
从Python的Zen中:
美丽胜于丑陋。
显式胜于隐式。
简单胜于复杂。
可读性很重要。
希望这可以帮助!
这是一个解决方案。 它需要稍微修改基类以使子类具有灵活性。
它还为子类提供了一个“丑陋”的接口(args a,b,c,d,e,f,g,h
是必需的,但签名中没有)。 但是子类通常比基类更内部,因此丑陋就可以了。
class A:
def __init__(self,a,b,c,d,e, **extra_args):
# ... use params here ... extra_args are not used at all here.
pass
class B(A):
def __init__(self,*args, **kwargs):
super().__init__(*args, **kwargs)
f= kwargs["f"]
g= kwargs["g"]
h= kwargs["h"]
# do something with params f,g,h
pass
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.