一部のメソッドの実行をブロックするラッパーを作成しようとしています。古典的な解決策は、次のパターンを使用することです。
class RestrictingWrapper(object):
def __init__(self, w, block):
self._w = w
self._block = block
def __getattr__(self, n):
if n in self._block:
raise AttributeError, n
return getattr(self._w, n)
このソリューションの問題は、すべての呼び出しで発生するオーバーヘッドであるため、MetaClass を使用して同じタスクを実行しようとしています。これが私の解決策です:
class RestrictingMetaWrapper(type):
def __new__(cls, name, bases, dic):
wrapped = dic['_w']
block = dic.get('_block', [])
new_class_dict = {}
new_class_dict.update(wrapped.__dict__)
for attr_to_block in block:
del new_class_dict[attr_to_block]
new_class_dict.update(dic)
return type.__new__(cls, name, bases, new_class_dict)
シンプルなクラスで完璧に動作します:
class A(object):
def __init__(self, i):
self.i = i
def blocked(self):
return 'BAD: executed'
def no_blocked(self):
return 'OK: executed'
class B(object):
__metaclass__ = RestrictingMetaWrapper
_w = A
_block = ['blocked']
b= B('something')
b.no_blocked # 'OK: executed'
b.blocked # OK: AttributeError: 'B' object has no attribute 'blocked'
ndarray
問題は、numpyのような「より複雑な」クラスで発生します。
class NArray(object):
__metaclass__ = RestrictingMetaWrapper
_w = np.ndarray
_block = ['max']
na = NArray() # OK
na.max() # OK: AttributeError: 'NArray' object has no attribute 'max'
na = NArray([3,3]) # TypeError: object.__new__() takes no parameters
na.min() # TypeError: descriptor 'min' for 'numpy.ndarray' objects doesn't apply to 'NArray' object
他のクラス (例: pandas.Series) は、指定されたメソッドをブロックしないなどの奇妙なエラーが発生するため、メタクラスが適切に定義されていないと思います。
エラーの場所を見つけることができますか? この問題を解決するための他のアイデアはありますか?
更新: nneonneo のソリューションはうまく機能しますが、ラップされたクラスは、クラス定義内のいくつかの黒魔術でブロッカーを壊す可能性があるようです。
nneonneo のソリューションを使用する:
import pandas
@restrict_methods('max')
class Row(pandas.Series):
pass
r = Row([1,2,3])
r.max() # BAD: 3 AttributeError expected