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

标签 python oop inheritance

A.__init__ 中调用 self.func(argument):

class A(object):
    def __init__(self, argument, key=0):
        self.func(argument)
    def func(self, argument):
        #some code here

我想更改 BA.func 的签名。 B.funcB.__init__ 中通过 A.__init__ 被调用:

class B(A):
    def __init__(self, argument1, argument2, key=0):
        super(B, self).__init__(argument1, key)  # calls A.__init__
    def func(self, argument1, argument2):
        #some code here

显然,这是行不通的,因为 B.func 的签名需要两个参数,而 A.__init__ 用一个参数调用它。我该如何解决这个问题?还是我设计类(class)的方式有问题?

keyA.__init__ 的默认参数。 argument2 不适用于 keyargument2B 采用但 A 不采用的额外参数。 B 也接受 key 并为其设置默认值。

另一个约束是我不想更改 A.__init__ 的签名。 key 通常是 0。所以我想让用户能够编写 A(arg) 而不是 A(arg, key=0)

最佳答案

一般来说,在子类之间更改方法的签名打破了子类上的方法实现与父类上的方法相同的 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=keyB 传递 key

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

class A(object):
    def __init__(self, argument, *extra, key=0):
        self.func(argument, *extra)

我也会给 func() 一个 *extra 参数,这样它的接口(interface)在 AB;它只是忽略为 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>

关于python - 更改在基类的 __init__ 中调用的函数的签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36314522/

相关文章:

python - 判断线程是否已经启动

Java 与 OO 设计

C++ 在堆栈中存储包含多态属性的类对象

python - Python 中列表的语法

Python 3.3 if/else/elif

python - tensorflow 中 numpy.newaxis 的替代方案是什么?

java - 使用高级编程语言的简化 MIPS CPU

java - 以 Parent 和 Child 类作为参数的方法重载

python - Django 管理员。以相同的形式创建父级和子级

java - 子类的对象创建是否创建父类(super class)的对象,如果是,是否可以在子类中访问它?