跳过ndarray子类numpy的__new__(或可能会覆盖/限定在C或用Cython班)(Ski

2019-10-18 12:57发布

终极目标:有isinstance(MyClass(), np.ndarray)issubclass(MyClass, np.ndarray)都返回True MyClass呼叫np.ndarray.__new__()


比方说,我已经实现的所有方法numpy.ndarray ,我想设置它,这样它会通过isinstance检查ndarray ,但我希望它实际调用__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__()

这工作,如果它是子类对象的类:

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

BlockingClass2() # No error

我敢肯定,这是因为ndarray是一个C类,所以我想在C类中重写它(或,优选地,用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__new__ ? 也许我可以cimport一个函数来实例化类没有往上走的MRO?

Answer 1:

我不知道是否有可能以假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


Answer 2:

你都不可能假冒isinstance在Python,但你肯定不能创建一个类,将工作在numpy的本机代码相同,而无需调用它的__new__

我想一切复杂的,但后来意识到一些您所呼叫的功能也可能会返回ndarray ; 如果你想他们完全取代,那么你可以将猴补丁模块numpy的有你的类,而不是,这可能是唯一的出路; 或与元类的一类,有一个子类钩子,会说,原来ndarray和你的类是相同的两个实例模块更换ndarray ...

或者,如果只有isinstance是令人不安的,然后做一些事情真的很肮脏,并尝试

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


文章来源: Skip numpy __new__ in ndarray subclass (or possibly overriding/defining classes in C or cython)