元のクラスに基づいてヘルパーメソッドを追加するために、メタクラスを使用したいと思います。追加したいメソッドがself.__attributeName
を使用する場合、AttributeError
を取得します(名前マングリングのため)が、既存の同一のメソッドの場合、これは問題ではありません。
これは簡単な例です
# Function to be added as a method of Test
def newfunction2(self):
"""Function identical to newfunction"""
print self.mouse
print self._dog
print self.__cat
class MetaTest(type):
"""Metaclass to process the original class and
add new methods based on the original class
"""
def __new__(meta, name, base, dct):
newclass = super(MetaTest, meta).__new__(
meta, name, base, dct
)
# Condition for adding newfunction2
if "newfunction" in dct:
print "Found newfunction!"
print "Add newfunction2!"
setattr(newclass, "newfunction2", newfunction2)
return newclass
# Class to be modified by MetaTest
class Test(object):
__metaclass__ = MetaTest
def __init__(self):
self.__cat = "cat"
self._dog = "dog"
self.mouse = "mouse"
def newfunction(self):
"""Function identical to newfunction2"""
print self.mouse
print self._dog
print self.__cat
T = Test()
T.newfunction()
T.newfunction2() # AttributeError: 'Test' object has no attribute '__cat'
newfunction2
を使用できるself.__cat
を追加する方法はありますか?
(self.__cat
の名前をself._cat
に変更せずに。)
そして、おそらくもっと基本的なことですが、self.__cat
がTest
の一部になっているのに、なぜnewfunction2
が両方のケースで同じように扱われないのでしょうか。
名前のマングリングは、クラスのメソッドがコンパイルされるときに発生します。 __foo
のような属性名は_ClassName__foo
に変換されます。ここで、ClassName
は、メソッドが定義されているクラスの名前です。他のオブジェクトの属性には名前マングリングを使用できることに注意してください。
コードでは、newfunction2
の名前マングリングは機能しません。これは、関数がコンパイルされるときに、それがクラスの一部ではないためです。したがって、__cat
のルックアップは、__Test_cat
で行ったようにTest.__init__
に変換されません。必要に応じて、属性名のマングルバージョンを明示的に検索できますが、newfunction2
を汎用にし、複数のクラスに追加できるようにする必要があるようです。残念ながら、それは名前マングリングでは機能しません。
実際、クラスで定義されていないコードが属性にアクセスできないようにすることが、名前マングリングを使用する理由です。通常、プロキシまたはミックスインタイプを作成していて、内部使用属性をプロキシまたはミックスインしているクラスの属性と衝突させたくない場合にのみ、気にする価値があります(これはわかりません)。あらかじめ)。
両方の質問に答えるには:
self.__cat
_から_newfunction2
_に呼び出す必要がある場合は、_self._Test__cat
_を変更する必要があります。このマングリングは、クラスの定義内で発生する限り、識別子の構文上の位置に関係なく実行されます。
名前が壊れた名前に遭遇したとき、通訳がどこを読んでいるかは問題ではないと言っています。 名前がマングルされるのはifクラスの定義で発生する場合のみです。 、 そうではありません。クラス定義の直接「下」ではないため。したがって、_self.__cat
_を読み取ると、_self.__cat
_に保持され、notテキストで_self._Test__cat
_に置き換えられます。 Test
クラス内で定義されていないためです。
<Test instance>._Test__cat
を使用して、Test
クラスから__cat
属性にアクセスできます。 (ここで、<Test instance>
はself
またはTest
クラスの他のインスタンスに置き換えられます)
詳細については、 Python doc をご覧ください。