我有一个班级A
。在__init__
的{{1}}中,我调用方法A
。
self.func(argument)
类class A(object):
def __init__(self, argument, key=0):
self.func(argument)
是B
的子类。在A
中,我想更改B
的签名。当我从func
调用A
的构造函数时调用它。
B
显然,这不起作用,因为class B(A):
def __init__(self, argument1, argument2, key=0):
super(B, self).__init__(argument1, key) # can't send argument 2 to __init__ of A
def func(self, argument1, argument2):
#some code here
的签名需要2个参数。我该如何解决这个问题?或者我设计课程的方式有什么不对吗?
func
是A的key
的默认参数。__init__
不适用于argument2
。 key
是B所采用的额外参数,但A不是。 B也需要argument2
并且具有默认值。
另一个限制是我不想更改A的签名。key
通常是key
。因此,我希望用户能够编写0
而不是A(arg)
。
答案 0 :(得分:4)
一般来说,在子类之间更改方法的签名会打破期望子类上的方法实现与父级上的方法相同的API。
但是,您可以重新设置A.__init__
以允许任意额外参数,并将其传递给self.func()
:
class A(object):
def __init__(self, argument, *extra, **kwargs):
key = kwargs.get('key', 0)
self.func(argument, *extra)
# ...
class B(A):
def __init__(self, argument1, argument2, key=0):
super(B, self).__init__(argument1, argument2, key=key)
# ...
传递给super(B, self).__init__()
的第二个参数随后会在extra
元组中捕获,并在self.func()
之外应用于argument
。
在Python 2中,为了能够使用extra
,您需要切换到使用**kwargs
,否则key
将始终捕获第二个位置参数。请务必使用key
从B
传递key=key
。
在Python 3中,您不受此限制的约束;将*args
放在key=0
之前,并且只在调用中使用key
作为关键字参数:
class A(object):
def __init__(self, argument, *extra, key=0):
self.func(argument, *extra)
我也给func()
一个*extra
参数,这样它的界面在A
和B
之间基本保持不变;它只是忽略了传递给A
的第一个参数之外的任何内容,超出了B
的前两个参数:
class A(object):
# ...
def func(self, argument, *extra):
# ...
class B(A):
# ...
def func(self, argument1, argument2, *extra):
# ...
Python 2演示:
>>> class A(object):
... def __init__(self, argument, *extra, **kwargs):
... key = kwargs.get('key', 0)
... self.func(argument, *extra)
... def func(self, argument, *extra):
... print('func({!r}, *{!r}) called'.format(argument, extra))
...
>>> class B(A):
... def __init__(self, argument1, argument2, key=0):
... super(B, self).__init__(argument1, argument2, key=key)
... def func(self, argument1, argument2, *extra):
... print('func({!r}, {!r}, *{!r}) called'.format(argument1, argument2, extra))
...
>>> A('foo')
func('foo', *()) called
<__main__.A object at 0x105f602d0>
>>> B('foo', 'bar')
func('foo', 'bar', *()) called
<__main__.B object at 0x105f4fa50>
答案 1 :(得分:0)
您的设计似乎存在问题。以下可能会解决您的具体情况,但似乎进一步延续了糟糕的设计。请注意直接调用Parent.method
。
>>> class Parent:
def __init__(self, a, b=None):
Parent.method(self, a)
self.b = b
def method(self, a):
self.location = id(a)
>>> class Child(Parent):
def __init__(self, a):
super().__init__(a, object())
def method(self, a, b):
self.location = id(a), id(b)
>>> test = Child(object())
请考虑在您要覆盖的方法的第二个参数中添加默认参数。否则,设计您的类并以不同方式调用结构。重组可能会消除这个问题。
答案 2 :(得分:0)
实际上我会在A的__init__
中设置一个额外的布尔参数来控制func的调用,然后从B的__init__
class A(object):
def __init__(self, argument, key=0, call_func=True):
if call_func:
self.func(argument)
class B(A):
def __init__(self, argument):
argument1, argument2 = argument, 'something else'
super(B, self).__init__(argument1, argument2, call_func=False)