인스턴스 수준에서 메서드 재정의
Python에서 인스턴스 수준에서 클래스 메서드를 재정의하는 방법이 있습니까? 예를 들면 :
class Dog:
def bark(self):
print "WOOF"
boby = Dog()
boby.bark() # WOOF
# METHOD OVERRIDE
boby.bark() # WoOoOoF!!
표시된대로이 작업을 수행하지 마십시오. 인스턴스를 클래스와 다른 것으로 monkeypatch하면 코드를 읽을 수 없게됩니다.
monkeypatched 코드를 디버깅 할 수 없습니다.
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"
유형 모듈에서 MethodType을 사용해야합니다. 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!!
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
필요한 경우 함수 내 에서 변수 를 사용할 수 있습니다 . 이 하나의 인스턴스 객체에 대해서만 메서드를 재정의하기 때문에이 방법이 더 간단하고를 사용하는 것과 정확히 동일한 효과가 self
있습니다.
@codelogic의 탁월한 대답을 설명하기 위해 더 명시적인 접근 방식을 제안합니다. 이는 .
인스턴스 속성으로 액세스 할 때 연산자가 클래스 메서드를 바인딩하기 위해 철저하게 수행 하는 동일한 기술입니다. 단, 메서드는 실제로 클래스 외부에서 정의 된 함수입니다.
@codelogic의 코드로 작업 할 때 유일한 차이점은 메서드가 바인딩되는 방식입니다. 함수와 메서드가 Python에서 데이터가 아닌 설명 자라는 사실을 사용하고 메서드 를 호출합니다 __get__
. 특히 원본과 대체 모두 동일한 서명을 가지고 있습니다. 즉, 대체를 전체 클래스 메서드로 작성하여 .NET을 통해 모든 인스턴스 속성에 액세스 할 수 있습니다 self
.
클래스 Dog : def bark (self) : "Woof"인쇄 def new_bark (self) : "Woof Woof"인쇄 foo = Dog () # "멍청이" foo.bark () #이 개체에 대해서만 bark를 new_bark로 바꿉니다. foo.bark = new_bark .__ get __ (foo, Dog) foo.bark () # "Woof Woof"
바인딩 된 메서드를 인스턴스 속성에 할당하여 메서드 재정의에 대한 거의 완전한 시뮬레이션을 만들었습니다. 누락 된 편리한 기능 중 하나 super
는 클래스 정의에 있지 않기 때문에 인수가없는 버전에 대한 액세스 입니다. 또 다른 한 가지는 __name__
바인딩 된 메서드 의 속성이 클래스 정의 에서처럼 재정의하는 함수의 이름을 사용하지 않지만 수동으로 설정할 수 있다는 것입니다. 세 번째 차이점은 수동으로 바인딩 된 메서드가 함수 인 일반 속성 참조라는 것입니다. .
운영자는 아무것도하지 않습니다하지만 참조를 가져옵니다. 반면에 인스턴스에서 일반 메서드를 호출 할 때 바인딩 프로세스는 매번 새로운 바인딩 된 메서드를 만듭니다.
그런데 이것이 작동하는 유일한 이유는 인스턴스 속성이 비 데이터 설명자를 재정의하기 때문 입니다. 데이터 디스크립터에는 __set__
메서드가 있지만 (다행히도) 메서드에는 없습니다. 클래스의 데이터 설명자는 실제로 모든 인스턴스 속성보다 우선합니다. 이것이 속성에 할당 할 수있는 이유입니다. 할당을 __set__
시도 할 때 해당 메서드가 호출됩니다. 저는 개인적으로 이것을 한 단계 더 나아가 인스턴스의 기본 속성의 실제 값을 숨기고 싶습니다 __dict__
. 속성이 그림자를 가리기 때문에 정상적인 방법으로는 액세스 할 수 없습니다.
이것은 매직 (이중 밑줄) 방법에 대해 무의미하다는 것을 명심해야 합니다 . 물론 매직 메서드는 이런 방식으로 재정의 될 수 있지만이를 사용하는 작업은 유형 만 확인합니다. 예를 들어 __contains__
인스턴스에서 특별한 것을 설정할 수 있지만 호출 x in instance
하면이를 무시하고 type(instance).__contains__(instance, x)
대신 사용 합니다. 이것은 Python 데이터 모델에 지정된 모든 매직 메서드에 적용됩니다 .
함수는 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
functool.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!!
Though I liked the inheritance idea from S. Lott and agree with the 'type(a)' thing, but since functions too have accessible attributes, I think the it can be managed this way:
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__
and the output is :
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
Dear this is not overriding you are just calling the same function twice with the object. Basically overriding is related to more than one class. when same signature method exist in different classes then which function your are calling this decide the object who calls this. Overriding is possible in python when you make more than one classes are writes the same functions and one thing more to share that overloading is not allowed in python
I found this to be the most accurate answer to the original question
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()
참고URL : https://stackoverflow.com/questions/394770/override-a-method-at-instance-level
'developer tip' 카테고리의 다른 글
리플렉션을 사용하여 선언 순서대로 속성 가져 오기 (0) | 2020.10.26 |
---|---|
메인 콘텐츠 div를 CSS로 화면 높이를 채우는 방법 (0) | 2020.10.25 |
LR (0)과 SLR 구문 분석의 차이점은 무엇입니까? (0) | 2020.10.25 |
이전 달의 모든 행을 가져 오는 쿼리 (0) | 2020.10.25 |
Twitter Bootstrap으로 테이블에 스타일 적용 (0) | 2020.10.25 |