更改基类的__init__中调用的函数的签名

Swe*_*abh 4 python oop inheritance

我上课A。在中__init__A我称为方法self.func(argument)

class A(object):
    def __init__(self, argument, key=0):
        self.func(argument)
Run Code Online (Sandbox Code Playgroud)

B是的子类A。在中B,我想更改的签名func。当我调用Afrom 的构造函数时会调用它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
Run Code Online (Sandbox Code Playgroud)

显然,这是行不通的,因为Expect的签名func需要2个参数。我该如何解决?还是我设计课程的方式有问题?

key是A的默认参数__init__argument2不适用于keyargument2是B接受而A则没有的额外论点。B也接受key并且具有默认值。

另一个限制是我不想更改A.的签名,key通常为0。因此,我希望允许用户能够编写A(arg)而不是A(arg, key=0)

Mar*_*ers 5

一般来说,在子类之间更改方法的签名会破坏对子类上的方法实现与父类上的API相同的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)
    # ...
Run Code Online (Sandbox Code Playgroud)

传递给第二个参数super(B, self).__init__(),然后在所捕获的extra元组,并应用到self.func()除了argument

在Python 2中,要使其能够使用extra,就需要切换到using **kwargs,否则key总是会捕获第二个位置参数。确保传递keyBkey=key

在Python 3中,您不受此限制的约束;放在调用*args之前key=0并且仅用key作关键字参数:

class A(object):
    def __init__(self, argument, *extra, key=0):
        self.func(argument, *extra)
Run Code Online (Sandbox Code Playgroud)

我也要提供func()一个*extra参数,以便它的接口在A和之间基本上保持不变B。它只会忽略传递给for的第一个参数以及传递给for A的前两个参数之外的所有内容B

class A(object):
    # ...
    def func(self, argument, *extra):
        # ...

class B(A):
    # ...
    def func(self, argument1, argument2, *extra):
        # ...
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)