__cinit__() 在扩展 Cython 类时恰好采用 2 个位置参数

3 python runtime-error subclass cython scikit-learn

我想扩展 scikit-learn 的ClassificationCriterion类,它被定义为内部模块中的 Cython 类sklearn.tree._criterion。我想在 Python 中做到这一点,因为通常我无法访问 sklearn 的 pyx/pxd 文件(所以我不能访问cimport它们)。但是,当我尝试扩展时ClassificationCriterion,出现错误TypeError: __cinit__() takes exactly 2 positional arguments (0 given)。下面的 MWE 重现了错误,并显示错误发生__new____init__.

有没有办法像这样扩展 Cython 类?

from sklearn.tree import DecisionTreeClassifier
from sklearn.tree._criterion import ClassificationCriterion

class MaxChildPrecision(ClassificationCriterion):
    def __new__(self, *args, **kwargs):
        print('new')
        super().__new__(MaxChildPrecision, *args, **kwargs)

    def __init__(self, *args, **kwargs):
        print('init')
        super(MaxChildPrecision).__init__(*args, **kwargs)

clf = DecisionTreeClassifier(criterion=MaxChildPrecision())
Run Code Online (Sandbox Code Playgroud)

Dav*_*idW 5

有两个问题。首先,ClassificationCriterion它的构造函数需要两个特定的参数,你没有传递它。您必须弄清楚这些参数代表什么并将它们传递给基类。

其次,有一个 Cython 问题。如果我们查看如何使用的描述,__cinit__那么我们会看到:

传递给构造函数的任何参数都将传递给__cinit__()方法和__init__()方法。如果您期望在 Python 中对您的扩展类型进行子类化,您可能会发现提供__cinit__()方法***参数很有用,以便它可以接受和忽略额外的参数。否则,任何具有不同签名的init () 的Python 子类都必须覆盖__new__()以及__init__()

不幸的是,sklearn 的作者没有提供***参数,所以你必须覆盖__new__. 这样的事情应该工作:

class MaxChildPrecision(ClassificationCriterion):
    def __init__(self,*args, **kwargs):
        pass

    def __new__(cls,*args,**kwargs):
        # I have NO IDEA if these arguments make sense!
        return super().__new__(cls,n_outputs=5,
                           n_classes=np.ones((2,),dtype=np.int))
Run Code Online (Sandbox Code Playgroud)

我将必要的参数传递给ClassificationCriterionin__new____init__按照我认为合适的方式处理其余的参数。我不需要调用基类__init__(因为基类没有定义__init__)。