Python'da örnek düzeyinde bir sınıf yöntemini geçersiz kılmanın bir yolu var mı? Örneğin:
class Dog:
def bark(self):
print "WOOF"
boby = Dog()
boby.bark() # WOOF
# METHOD OVERRIDE
boby.bark() # WoOoOoF!!
Yanıtlar:
Lütfen bunu gösterildiği gibi yapmayın. Sınıftan farklı olacak bir örnek eklediğinizde kodunuz okunamaz hale gelir.
Monkeypatched kodda hata ayıklayamazsınız.
bobyVe içinde bir hata bulduğunuzdaprint type(boby) , bunun bir köpek, ama kabuğu doğru değil gibi anlaşılmaz bir sebeple (b) (a) göreceksiniz. Bu bir kabus. Bunu yapma.
Lütfen bunun yerine bunu yapın.
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!!
Evet mümkün:
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"
funcTypeişe yaradığını ve neden gerekli olduğunu açıklayın .
funcType = types.MethodTypeiçe aktardıktan sonra types) kullanarak biraz daha basit ve daha açık hale getirilebileceğini düşünüyorum funcType = type(Dog.bark).
__get__, örneğe bağlamak için işlevi çağırabilirsiniz .
Kullanmanız gerekir MethodType gelen typesmodül. Bunun amacı, MethodTypeörnek düzeyindeki yöntemlerin üzerine yazmaktır (böyleceself üzerine yazılan yöntemlerde mevcut olabilir).
Aşağıdaki örneğe bakın.
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'in mükemmel cevabını açıklamak için daha açık bir yaklaşım öneriyorum. Bu, .bir örnek özniteliği olarak eriştiğinizde , operatörün bir sınıf yöntemini bağlamak için kapsamlı bir şekilde gittiği aynı tekniktir , ancak yönteminizin aslında bir sınıfın dışında tanımlanmış bir işlev olması gerekir.
@ Codelogic'in koduyla çalışırken, tek fark yöntemin nasıl bağlandığıdır. Python'da işlevlerin ve yöntemlerin veri tanımlayıcılar olmadığı gerçeğini kullanıyorum ve yöntemi çağırıyorum __get__. Özellikle, hem orijinalin hem de değiştirilenin aynı imzalara sahip olduğuna dikkat edin, yani değiştirmeyi tam sınıf yöntemi olarak yazabilir, tüm örnek özniteliklerine aracılığıyla erişebilirsiniz.self .
sınıf Köpek:
def bark (kendi):
"Hav" yazdır
def new_bark (kendi):
"Hav Hav" yazdır
foo = Köpek ()
# "Hav"
foo.bark ()
# sadece bu nesne için kabuğu new_bark ile değiştirin
foo.bark = new_bark .__ get __ (foo, Dog)
foo.bark ()
# "Hav! Hav"
Bağlı yöntemi bir örnek niteliğine atayarak, bir yöntemi geçersiz kılmak için neredeyse eksiksiz bir simülasyon yaratmış olursunuz. Eksik olan kullanışlı bir özellik, supersınıf tanımında olmadığınız için argüman içermeyen sürümüne erişimdir . Başka bir şey de, __name__bağlı yönteminizin özniteliğinin, sınıf tanımında olduğu gibi geçersiz kıldığı işlevin adını almayacağıdır, ancak yine de manuel olarak ayarlayabilirsiniz. Üçüncü fark, manuel olarak bağlanmış yönteminizin sadece bir işlev olan düz bir öznitelik referansı olmasıdır. .Operatör hiçbir şey yapmaz ama bu başvuru getir. Öte yandan bir örnekten normal bir yöntemi çağırırken, bağlama işlemi her seferinde yeni bir bağlı yöntem oluşturur.
Bu arada, bunun çalışmasının tek nedeni, örnek niteliklerinin veri olmayan tanımlayıcıları geçersiz kılmasıdır. Veri tanımlayıcıların __set__yöntemleri vardır, ancak bu yöntemlerin (neyse ki sizin için) yoktur. Sınıftaki veri tanımlayıcıları aslında herhangi bir örnek özniteliğine göre önceliklidir. Bir özelliğe atamanın nedeni budur: __set__bir atama yapmaya çalıştığınızda onların yöntemi çağrılır. Ben şahsen bunu bir adım daha ileri götürmeyi ve özniteliğin __dict__tam olarak onu gölgelediği için normal yollarla erişilemez olduğu örnekteki temel niteliğin gerçek değerini gizlemeyi seviyorum .
Bunun sihir (çift alt çizgi) yöntemleri için anlamsız olduğunu da aklınızda bulundurmalısınız . Bu şekilde sihirli yöntemler elbette geçersiz kılınabilir, ancak onları kullanan işlemler yalnızca türe bakar. Örneğin, __contains__örneğinizde özel bir şeye ayarlayabilirsiniz , ancak çağrı x in instancebunu dikkate almaz ve type(instance).__contains__(instance, x)onun yerine kullanır. Bu, Python veri modelinde belirtilen tüm sihirli yöntemler için geçerlidir .
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İhtiyaç duyarsanız, fonksiyonun içindeki değişkeni kullanabilirsiniz . Yöntemi yalnızca bu tek örnek nesne için geçersiz kıldığınız için, bu yol daha basittir ve kullanmakla tamamen aynı etkiye sahiptir self.
patchingve bunu yapmanın doğru yolu budur (örneğin boby = Dog()ve boby.bark = new_bark). Kontroller için birim testinde inanılmaz derecede faydalıdır . Daha fazla açıklama için bkz. Tryolabs.com/blog/2013/07/05/run-time-method-patching-python (örnekler) - hayır, bağlantılı site veya yazara bağlı değilim.
functools.partialBurada kimse bahsetmediğinden :
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'da işlevler birinci sınıf nesneler olduğundan, sınıf nesnenizi başlatırken bunları iletebilir veya belirli bir sınıf örneği için istediğiniz zaman geçersiz kılabilirsiniz:
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()
ve sonuçlar
calling original bark
woof
calling the new bark
wooOOOoof
calling another new
nowoof
S. Lott'un kalıtım fikrini sevmeme ve 'tip (a)' konusuna katılmama rağmen, işlevlerin de erişilebilir nitelikleri olduğundan, bunun şu şekilde yönetilebileceğini düşünüyorum:
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__
ve çıktı:
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
Sevgili, bu geçersiz kılmıyor, sadece aynı işlevi nesne ile iki kez çağırıyorsunuz. Temelde geçersiz kılma birden fazla sınıfla ilgilidir. aynı imza yöntemi farklı sınıflarda mevcut olduğunda, hangi işlevi çağırdığınızı, bunu kimin çağırdığına karar verin. Python'da, birden fazla sınıf oluşturduğunuzda geçersiz kılma mümkündür, aynı işlevleri yazar ve python'da bu aşırı yüklemeye izin verilmeyen bir şey daha paylaşılır.
Bunu orijinal soruya verilen en doğru cevap olarak buldum
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()