ショート バージョン: インスタンスにバインドされた外部メソッドは、 を介してプライベート変数に直接アクセスできませんself.__privatevarname
。これは機能ですか、それともバグですか?
拡張版 (説明と例付き) :
Python : バインドされていないメソッドをバインドしますか? で、Alex Martelli が関数をインスタンスにバインドする簡単な方法を説明しています。
このメソッドを使用すると、外部関数を使用してクラスにインスタンス メソッドを設定できます (図 2 __init__
)。
ただし、インスタンスにバインドされている関数がプライベート変数にアクセスする必要がある場合、これは失敗します。これは、 のコンパイル手順で名前マングリングが発生し_Py_Mangle
、関数が を呼び出す機会がないため__getattribute__('_classname__privatevarname')
です。
たとえば、プライベート インスタンス変数にアクセスする単純な外部加算関数を定義するとします__obj_val
。
def add_extern(self, value):
return self.__obj_val + value
クラス定義で__init__
同様のインスタンスメソッドを定義しながら、それを各インスタンスにバインドしますadd_intern
class TestClass(object):
def __init__(self, object_value):
self.__obj_val = object_value
self.add_extern = add_extern.__get__(self, TestClass)
def add_intern(self, value):
return self.__obj_val + value
内部メソッドは機能しますが、外部バインド メソッドは例外を発生させます。
>>> t = TestClass(0)
>>> t.add_intern(1)
1
>>> t.add_extern(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in add_extern
AttributeError: 'TestClass' object has no attribute '__obj_val'
POSTSCRIPT__getattribute__
:マングリングを行うようにオーバーライドすることで、この欠点を克服できます。
class TestClass(object):
...
def __getattribute__(self, name):
try:
return super(TestClass, self).__getattribute__(name)
except AttributeError:
# mimic behavior of _Py_Mangle
if not name.startswith('__'): # only private attrs
raise
if name.endswith('__'): # don't mangle dunder attrs
raise
if '.' in name: # don't mangle for modules
raise
if not name.lstrip('_'): # don't mangle if just underscores
raise
mangled_name = '_{cls_name}{attr_name}'.format(
cls_name=self.__class__.__name__, attr_name=name)
return super(TestClass, self).__getattribute__(mangled_name)
ただし、これは変数を外部の呼び出し元に非公開のままにするわけではありません。これは望ましくありません。