对于每个ufunc都有相同的输入参数、属性,这个可以去文档中看,主要是每个函数还对应了4个method:
|name | description| |-|-| |ufunc.reduce(array[, axis, dtype, out,
…])|Reduces array’s dimension by one, by applying ufunc along one axis.|
|ufunc.accumulate(array[, axis, dtype, out])|Accumulate the result of
applying the operator to all elements.| |ufunc.reduceat(array, indices[,
axis, …])|Performs a (local) reduce with specified slices over a single
axis.| |ufunc.outer(A, B, /, **kwargs)|Apply the ufunc op to all pairs
(a, b) with a in A and b in B.| |ufunc.at(a, indices[, b])|Performs
unbuffered in place operation on operand ‘a’ for elements specified by
‘indices’. |
接下来我们适配一个__call__方法,也就是直接调用的方法:
from numbers import Number
classPEArray: def__init__(self, height, width, spad_size, pe=None): self._h = height self._w = width self._spad = spad_size if pe isnotNone: self._pe = pe else: self._pe = np.random.rand(self._h, self._w)
def__array_ufunc__(self, ufunc, method, *inputs, **kwargs): if method == '__call__': scalars = [] objects = [] forinputin inputs: ifisinstance(input, Number): scalars.append(input) elifisinstance(input, self.__class__): ifinput._pe.shape != self._pe.shape: raise ValueError("inconsistent shape") objects.append(input._pe) else: return NotImplementedError("not support the other type") return self.__class__(self._h, self._w, self._spad, ufunc(*objects, *scalars, **kwargs)) else: return NotImplementedError("now only support __call__!")
def__array_function__(self, func, types, args, kwargs): if func notin HANDLED_FUNCTIONS: returnNotImplemented # Note: this allows subclasses that don't override # __array_function__ to handle DiagonalArray objects. ifnotall(issubclass(t, self.__class__) for t in types): returnNotImplemented return HANDLED_FUNCTIONS[func](*args, **kwargs)
import numpy as np # create a completely useless ndarray subclass classC(np.ndarray): pass # create a standard ndarray arr = np.zeros((3,)) # take a view of it, as our useless subclass c_arr = arr.view(C) type(c_arr)
__main__.C
3. from template,
比如copy,slice,ufunc都会生成
v = c_arr[1:] print(type(v)) # 切片后还是老类别,那是因为切片只是原始数组中的一个数组投影.
classC: def__new__(cls, *args): print('Cls in __new__:', cls) print('Args in __new__:', args) # The `object` type __new__ method takes a single argument. returnobject.__new__(cls)
def__init__(self, *args): print('type(self) in __init__:', type(self)) print('Args in __init__:', args)
classC(np.ndarray): def__new__(cls, *args, **kwargs): print('In __new__ with class %s' % cls) returnsuper().__new__(cls, *args, **kwargs)
def__init__(self, *args, **kwargs): # in practice you probably will not need or want an __init__ # method for your subclass print('In __init__ with class %s' % self.__class__)
def__array_finalize__(self, obj): print('In array_finalize:') print(' self type is %s' % type(self)) print(' obj type is %s' % type(obj)) print("\nmethod 1 \n") c = C((1,2,3)) print("\nmethod 2 \n") np.arange(10).view(C) print("\nmethod 3 \n") cc = c[1:]
method 1
In __new__ with class <class '__main__.C'> In array_finalize: self type is <class '__main__.C'> obj type is <class 'NoneType'> In __init__ with class <class '__main__.C'>
method 2
In array_finalize: self type is <class '__main__.C'> obj type is <class 'numpy.ndarray'>
method 3
In array_finalize: self type is <class '__main__.C'> obj type is <class '__main__.C'>