1

最終的な目標: haveisinstance(MyClass(), np.ndarray)issubclass(MyClass, np.ndarray)both がを呼び出さTrue ずに 返されます。MyClassnp.ndarray.__new__()


のすべてのメソッドを実装したとしましょう。 のチェックにnumpy.ndarray合格するように設定したいのですが、実際にはから呼び出したくありませんisinstancendarray__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

がCクラスであるためだと確信しているのでndarray、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

isinstancePython で を偽造することはできますが、その__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 に答える