最终目标:让isinstance(MyClass(), np.ndarray)
和issubclass(MyClass, np.ndarray)
都返回True
而不 MyClass
致电np.ndarray.__new__()
。
假设我已经实施了numpy.ndarray
的所有方法,我想进行设置,以便isinstance
对ndarray
进行检查,但我 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?
答案 0 :(得分:2)
我不知道是否可以伪造isinstance
和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
答案 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