Parent class 在 child 之前调用

Parent class called before child

我正在创建一个继承自 PySndfile 的 child class,它将包含与 PySndfile class.

相关的额外功能

但是,当使用不适用于 PySndfile class 的关键字参数初始化 child class 时,参数似乎直接发送到 parent class,完全绕过 child 的 init(即不调用打印语句,不从 kwargs 中弹出参数并且不回溯完全参考child class。

如有任何帮助,我们将不胜感激。

ClassProblem.py:

from pysndfile import PySndfile

class AudioFile(PySndfile):
    def __init__(self, filename, mode, rms="123"):
        print 'AudioFile init called'
        self.rms = rms
        super(AudioFile, self).__cinit__(
                self, 
                filename, 
                mode=mode, 
                format=None,
                channels=None, 
                samplerate=None
                )

aa = AudioFile(
    "/path/to/audio/file.wav",
    'r',
    rms="456",
    )

产生错误:

Traceback (most recent call last):
  File "ClassProblem.py", line 18, in <module>
    rms="456",
  File "_pysndfile.pyx", line 564, in _pysndfile.PySndfile.__cinit__ (_pysndfile.cpp:3308)
TypeError: __cinit__() got an unexpected keyword argument 'rms'

PySndfile 似乎是一个 Cython 库。我对 Cython 一无所知,但从回溯中可以看出它使用 __cinit__ 而不是 __init__。您可能应该改写该方法。

您有效地将 **kwargs 传递给 PySndfile 构造函数,但它不知道如何处理特定于您的 class 的 rms 参数。我本地没有 PySndfile 但在网上快速浏览后,我看到 pyx 构造函数如下所示:

def __cinit__(self, filename, mode='r', int format=0,
             int channels=0, int samplerate=0):

这不是一个 *args, **kwargs 函数,可以接受任何参数,但它有一个固定的签名。我建议使用类似的构造函数更新 class,您可以向其中添加特定于 class:

的参数
def __init__(self, filename, mode='r', rms=0, format=0,
             channels=0, samplerate=0):

然后将所有参数传递给超级构造函数(除了rms,它不理解)。

根据 cython documentation:

,您似乎必须覆盖 __new__

If you anticipate subclassing your extension type in Python, you may find it useful to give the cinit() method * and ** arguments so that it can accept and ignore extra arguments. Otherwise, any Python subclass which has an init() with a different signature will have to override new() [1] as well as init(), which the writer of a Python class wouldn’t expect to have to do.

我通过将此问题发布到 /r/learnpython sub-reddit

找到了答案

用户 yes_or_gnome 很好地解释了为什么我需要覆盖 __new__ class 方法以及 __init__ 方法,并提供了示例代码.