1

最终目标: have isinstance(MyClass(), np.ndarray)and issubclass(MyClass, np.ndarray)both return True without MyClass call 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):通过

BlockingClassc定义的函数在哪里。我真的更喜欢在 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?

4

2 回答 2

2

我不知道是否可以伪造isinstanceand issubclass,但是在以下方法中,您可以定义您的类,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
于 2013-08-17T06:35:56.030 回答
1

您可以isinstance在 Python 中伪造 ,但如果不调用其__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
于 2013-08-17T03:07:23.027 回答