Pythonにインスタンスレベルでクラスメソッドをオーバーライドする方法はありますか?例えば:
class Dog:
def bark(self):
print "WOOF"
boby = Dog()
boby.bark() # WOOF
# METHOD OVERRIDE
boby.bark() # WoOoOoF!!
回答:
図のようにこれを行わないでください。インスタンスをクラスとは異なるものにモンキーパッチすると、コードが読み取れなくなります。
モンキーパッチされたコードをデバッグすることはできません。
bobyとprint type(boby)でバグを見つけると、(a)犬ですが、(b)なんらかの理由で、正しく吠えないことがわかります。これは悪夢です。それをしません。
代わりにこれを行ってください。
class Dog:
def bark(self):
print "WOOF"
class BobyDog( Dog ):
def bark( self ):
print "WoOoOoF!!"
otherDog= Dog()
otherDog.bark() # WOOF
boby = BobyDog()
boby.bark() # WoOoOoF!!
はい、それは可能です:
class Dog:
def bark(self):
print "Woof"
def new_bark(self):
print "Woof Woof"
foo = Dog()
funcType = type(Dog.bark)
# "Woof"
foo.bark()
# replace bark with new_bark for this object only
foo.bark = funcType(new_bark, foo, Dog)
foo.bark()
# "Woof Woof"
funcType、なぜそれが必要なのかを説明してください。
funcType = types.MethodType(インポート後types)を使用することで、これを少し簡単かつ明確にできると思いますfuncType = type(Dog.bark)。
__get__関数を呼び出して、インスタンスにバインドすることもできます。
モジュールからMethodTypeを使用する必要がありtypesます。の目的MethodTypeは、インスタンスレベルのメソッドを上書きselfすることです(上書きされたメソッドで使用できるようにするため)。
以下の例を参照してください。
import types
class Dog:
def bark(self):
print "WOOF"
boby = Dog()
boby.bark() # WOOF
def _bark(self):
print "WoOoOoF!!"
boby.bark = types.MethodType(_bark, boby)
boby.bark() # WoOoOoF!!
@codelogicの優れた答えを説明するために、より明確なアプローチを提案します。これは、.メソッドが実際にはクラスの外部で定義された関数になることを除いて、インスタンス属性としてアクセスするときにオペレーターがクラスメソッドをバインドするために徹底的に行うのと同じ手法です。
@codelogicのコードを使用する場合、唯一の違いはメソッドのバインド方法にあります。関数とメソッドがPythonの非データ記述子であるという事実を利用して、__get__メソッドを呼び出しています。特に、元の署名と置換の両方が同一のシグネチャを持っていることに注意してください。つまり、を介してすべてのインスタンス属性にアクセスし、完全なクラスメソッドとして置換を記述できますself。
クラス犬:
def bark(self):
「Woof」を印刷
def new_bark(self):
「WoofWoof」を印刷
foo = Dog()
#「ウーフ」
foo.bark()
#このオブジェクトの場合のみ、樹皮をnew_barkに置き換えます
foo.bark = new_bark .__ get __(foo、Dog)
foo.bark()
#「WoofWoof」
バインドされたメソッドをインスタンス属性に割り当てることにより、メソッドのオーバーライドのほぼ完全なシミュレーションを作成しました。欠落している便利な機能の1つsuperは、クラス定義に含まれていないため、引数のないバージョンへのアクセスです。もう1つのことは__name__、バインドされたメソッドの属性は、クラス定義の場合のように、オーバーライドする関数の名前を取りませんが、手動で設定することはできます。3番目の違いは、手動でバインドされたメソッドは、たまたま関数であるプレーンな属性参照であるということです。.オペレータは何もしませんが、その参照を取得します。一方、インスタンスから通常のメソッドを呼び出す場合、バインディングプロセスは毎回新しいバインドされたメソッドを作成します。
ちなみに、これが機能する唯一の理由は、インスタンス属性が非データ記述子をオーバーライドすることです。データ記述子には__set__メソッドがありますが、(幸いなことに)メソッドにはありません。クラス内のデータ記述子は、実際にはどのインスタンス属性よりも優先されます。これが、プロパティに割り当てることができる理由です__set__。割り当てを行おうとすると、そのメソッドが呼び出されます。私は個人的にこれをさらに一歩進めて、インスタンスの基になる属性の実際の値を非表示にするのが好きです。インスタンス__dict__は、プロパティがシャドウしているため、通常の方法ではアクセスできません。
また、これは魔法の(二重下線)メソッドには無意味であることも覚えておく必要があります。もちろん、マジックメソッドはこの方法でオーバーライドできますが、マジックメソッドを使用する操作はタイプのみを調べます。たとえば__contains__、インスタンスで特別なものに設定できますが、呼び出しx in instanceはそれを無視してtype(instance).__contains__(instance, x)代わりに使用します。これは、Pythonデータモデルで指定されているすべてのマジックメソッドに適用されます。
class Dog:
def bark(self):
print "WOOF"
boby = Dog()
boby.bark() # WOOF
# METHOD OVERRIDE
def new_bark():
print "WoOoOoF!!"
boby.bark = new_bark
boby.bark() # WoOoOoF!!
boby必要に応じて、関数内で変数を使用できます。この1つのインスタンスオブジェクトに対してのみメソッドをオーバーライドするため、この方法はより簡単で、を使用する場合とまったく同じ効果がありselfます。
functools.partialここでは誰も言及していないので:
from functools import partial
class Dog:
name = "aaa"
def bark(self):
print("WOOF")
boby = Dog()
boby.bark() # WOOF
def _bark(self):
print("WoOoOoF!!")
boby.bark = partial(_bark, boby)
boby.bark() # WoOoOoF!!
関数はPythonのファーストクラスオブジェクトであるため、クラスオブジェクトの初期化中にそれらを渡すか、特定のクラスインスタンスに対していつでもオーバーライドできます。
class Dog:
def __init__(self, barkmethod=None):
self.bark=self.barkp
if barkmethod:
self.bark=barkmethod
def barkp(self):
print "woof"
d=Dog()
print "calling original bark"
d.bark()
def barknew():
print "wooOOOoof"
d1=Dog(barknew)
print "calling the new bark"
d1.bark()
def barknew1():
print "nowoof"
d1.bark=barknew1
print "calling another new"
d1.bark()
結果は
calling original bark
woof
calling the new bark
wooOOOoof
calling another new
nowoof
S. Lottからの継承のアイデアが好きで、「type(a)」のことには同意しますが、関数にもアクセス可能な属性があるため、次のように管理できると思います。
class Dog:
def __init__(self, barkmethod=None):
self.bark=self.barkp
if barkmethod:
self.bark=barkmethod
def barkp(self):
"""original bark"""
print "woof"
d=Dog()
print "calling original bark"
d.bark()
print "that was %s\n" % d.bark.__doc__
def barknew():
"""a new type of bark"""
print "wooOOOoof"
d1=Dog(barknew)
print "calling the new bark"
d1.bark()
print "that was %s\n" % d1.bark.__doc__
def barknew1():
"""another type of new bark"""
print "nowoof"
d1.bark=barknew1
print "another new"
d1.bark()
print "that was %s\n" % d1.bark.__doc__
出力は次のとおりです。
calling original bark
woof
that was original bark
calling the new bark
wooOOOoof
that was a new type of bark
another new
nowoof
that was another type of new bark
これが元の質問に対する最も正確な答えであることがわかりました
https://stackoverflow.com/a/10829381/7640677
import a
def _new_print_message(message):
print "NEW:", message
a.print_message = _new_print_message
import b
b.execute()