在ndarray子类中跳过numpy __new__(或者可能在C或cython中覆盖/定义类)

时间:2013-08-17 02:54:33

标签: python class numpy subclass cython

最终目标:让isinstance(MyClass(), np.ndarray)issubclass(MyClass, np.ndarray)都返回True 而不 MyClass致电np.ndarray.__new__()


假设我已经实施了numpy.ndarray的所有方法,我想进行设置,以便isinstancendarray进行检查,但我 don' t 希望它实际从__new__拨打ndarray

最初,我在考虑这样的事情:

import numpy as np
class BlockingClass(np.ndarray):
    def __new__(cls, *args, **kwargs):
        return object.__new__(cls)

不幸的是,尝试实例化Dummy()会产生关于它不安全的错误:

TypeError: object.__new__(Dummy) is not safe, use numpy.ndarray.__new__()

如果它是一个子类object:

的类,则它可以工作
class BlockingClass2(object):
    def __new__(cls, *args, **kwargs):
        return object.__new__(cls)

BlockingClass2() # No error

我很确定这是因为ndarray是一个C类,所以我想在c-class(或者,最好是一个Cython类)中重写它并使用多重继承来获得类型检查在不致电__new__的情况下工作。所以我的课程将是:

类MyClass(BlockingClass,np.ndarray):     通

其中BlockingClass将是c定义的函数。我宁愿在Cython中这样做,但我无法弄清楚如何让它工作。我试过了:

cdef class BlockingClass:
    def __new__(cls, *args, **kwargs):
        return object.__new__(cls)

但是这会产生与__cinit__相同的“不安全”错误。

cdef class BlockingClass:
    def __cinit__(self, *args, **kwargs):
        # do stuff
        return self

但是,当BlockingClass使用定义__new__的对象进行多重继承的子类化时,仍会调用__new__方法。如果我不能在Cython中做到这一点,那么我需要定义一个基类的最小数量的C代码,通过多重继承,它会跳过ndarray的{​​{1}}?也许我可以插入一个函数来实例化该类而不需要上传mro?

2 个答案:

答案 0 :(得分:2)

我不知道是否可以伪造isinstanceissubclass,但在以下方法中,您可以定义您的类只传递您想要的参数np.ndarray.__new__

import numpy as np
class BlockingClass(np.ndarray):
    def __new__(cls, *args, **kwargs):
        ndarray_kw = ['shape', 'dtype',  'buffer' 'offset', 'strides', 'order']
        to_ndarray = {}
        to_myclass = {}
        for k,v in kwargs.items():
            if k not in ndarray_kw:
                to_myclass[k] = v
            else:
                to_ndarray[k] = v
        new = np.ndarray.__new__(cls, *args, **to_ndarray)
        for k,v in to_myclass.items():
            setattr(new, k, v)
        return new

    def __init__(self, *args, **kwargs):
        self.test = 1
        self.args = args
        self.kwargs = kwargs

答案 1 :(得分:1)

你可以伪造Python中的isinstance,但你肯定无法创建一个类似于numpy中的本机代码而不调用它的__new__

我在想一切复杂但是,然后意识到你正在调用的一些函数也可能返回ndarray;如果你想让它们完全被替换,那么你可以将numpy模块monkeypatch来代替你的类,这可能是唯一的方法;或者用一个带有元类的模块替换ndarray,该类具有一个子类钩子,它会说原始的ndarray和你的类都是相同的实例......

或者如果只是实例是令人不安的,那么做一些非常脏的事情,然后尝试

import __builtin__

_original_isinstance = __builtin__.isinstance
class FakeArray(object):
    pass

def isinstance(object, class_or_type):
    if _original_isinstance(object, tuple):
        if ndarray in class_or_type:
            class_or_type += (FakeArray,)

    else:
        if class_or_type is ndarray:
            class_or_type = (ndarray, FakeArray)

    return _original_isinstance(object, class_or_type)

__builtin__.isinstance = isinstance