인스턴스 수준에서 메서드 재정의
인스턴스 수준에서 클래스 메서드를 재정의하는 방법이 파이썬에 있습니까?예:
class Dog:
def bark(self):
print "WOOF"
boby = Dog()
boby.bark() # WOOF
# METHOD OVERRIDE
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을 사용해야 합니다.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의 훌륭한 답변을 설명하기 위해, 저는 좀 더 명확한 접근법을 제안합니다.▁the▁that▁technique▁same다▁this니기입술▁is▁the같과 같은 기술입니다..
연산자는 클래스 메소드를 인스턴스 속성으로 액세스할 때 클래스 메소드를 바인딩합니다. 단, 메소드는 클래스 외부에 정의된 함수가 됩니다.
@codelogic의 코드로 작업할 때 유일한 차이점은 메소드가 바인딩되는 방식입니다.나는 함수와 메서드가 파이썬에서 비데이터 설명자라는 사실을 사용하고 있으며,__get__
서명이 . 즉, 를 풀하여 모든 속성에 수 있습니다. 즉, 원본과 대체의 서명은 모두 동일합니다.self
.
클래스 도그:defbark(자체):"WOFF" 인쇄 defnew_messages(자체):"Woof Woof" 인쇄 foo = 개() "우프"푸우우우우 이 개체에 대해서만 bark를 new_back으로 바꿉니다.foo.foo = new_discovery.__get__(foo, Dog) 푸우우우우"우프 우프"
바인딩된 메서드를 인스턴스(instance) 특성에 할당함으로써 메서드를 재정의하는 거의 완전한 시뮬레이션을 만들 수 있습니다.누락된 한 가지 편리한 기능은 의 인수가 없는 버전에 액세스하는 것입니다.super
클래스 정의에 없기 때문입니다.또 다른 것은__name__
바인딩된 메서드의 속성은 클래스 정의에서와 같이 재정의하는 함수의 이름을 사용하지 않지만 수동으로 설정할 수 있습니다.세 번째 차이점은 수동으로 바인딩된 메소드가 우연히 함수가 되는 일반 속성 참조라는 것입니다..
연산자는 해당 참조만 가져옵니다.반면 인스턴스에서 일반 메서드를 호출할 때 바인딩 프로세스는 매번 새 바인딩 메서드를 만듭니다.
이 방법이 작동하는 유일한 이유는 인스턴스 속성이 데이터가 아닌 설명자를 재정의하기 때문입니다.데이터 설명자는 다음과 같습니다.__set__
(당신에게는 다행스럽게도) 그렇지 않은 방법.클래스의 데이터 설명자는 실제로 인스턴스 속성보다 우선합니다.할 수 입니다: 그들의 그렇때할수할있습다니당속성.__set__
할당을 시도할 때 메서드가 호출됩니다.을 한 더 에 있는 기본 .__dict__
부동산이 그림자를 드리우기 때문에 정상적인 수단으로 접근할 수 없는 경우.
또한 마법(더블 밑줄) 방법에는 의미가 없습니다.물론 이러한 방식으로 매직 메소드를 재정의할 수 있지만, 이 메소드를 사용하는 작업은 유형만 봅니다.예를 들어 다음과 같이 설정할 수 있습니다.__contains__
당신의 경우에 특별한 것으로, 하지만 부르는 것.x in instance
그것을 무시하고 사용할 것입니다.type(instance).__contains__(instance, x)
대신.이는 Python 데이터 모델에 지정된 모든 Magic 메서드에 적용됩니다.
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
.
표시된 대로 하지 마십시오.인스턴스를 클래스와 다르게 패치하면 코드를 읽을 수 없게 됩니다.
원숭이 패치 코드를 디버그할 수 없습니다.
에서 하면,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!!
아무도 여기에 언급하지 않기 때문에:
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
새 메서드 내부에서 이전 메서드를 호출해야 할 경우 주의하십시오.
import types
class Dog:
def bark(self):
print("WOOF")
boby = Dog()
boby.bark() # WOOF
def _bark(self):
self.bark()
print("WoOoOoF!!")
boby.bark = types.MethodType(_bark, boby)
boby.bark() # Process finished with exit code -1073741571 (0xC00000FD) [stack overflow]
# This also happens with the '__get__' solution
이러한 경우 다음을 사용할 수 있습니다.
def _bark(self):
Dog.bark(self)
print( "WoOoOoF!!") # Calls without error
하지만 이 이미 요?foo
의bark
방법?그리고나서Dog.bark(foo)
는 와동하않습다니지일않다▁the▁▁same와 하지 않습니다.foo.bark
, 이 두 가지 가장 쉬운 해결책은 두, 효과있은해가쉬책결운장는가에우경험지입니다.
# Save the previous definition before overriding
old_bark = foo.bark
def _bark(self):
old_bark()
print("WoOoOoF!!")
foo.bark = _bark
# Works for instance-overridden methods, too
대부분의 경우 하위 분류 및 사용super
이 상황을 처리하는 올바른 방법입니다.그러나 이러한 원숭이 패치가 필요할 때가 있으며, 사용자가 좀 더 주의하지 않으면 스택 오버플로 오류가 발생하여 실패할 수 있습니다.
S의 상속 아이디어가 마음에 들긴 했지만요.'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
친애하는 이것은 당신이 객체와 같은 함수를 두 번 호출하는 것을 무시하는 것이 아닙니다.기본적으로 재정의는 둘 이상의 클래스와 관련이 있습니다.동일한 서명 방법이 다른 클래스에 존재하는 경우 이를 호출하는 함수가 이를 호출하는 개체를 결정합니다.둘 이상의 클래스를 만들면 python에서 동일한 함수를 쓰고 python에서 오버로드가 허용되지 않는 공유할 한 가지를 더 쓸 때 재정의가 가능합니다.
저는 이것이 원래 질문에 대한 가장 정확한 대답이라는 것을 알았습니다.
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
'programing' 카테고리의 다른 글
배열을 오라클 프로시저로 전달 (0) | 2023.08.01 |
---|---|
iOS 시뮬레이터에 딥 링크를 전달하시겠습니까? (0) | 2023.08.01 |
캔버스의 컨텍스트를 가져오는 것과 동일한 jQuery (0) | 2023.07.27 |
부팅 시 스프링 보안 필터 체인 전에 필터 호출 (0) | 2023.07.27 |
파일 경로에서 이미지 보기를 표시하시겠습니까? (0) | 2023.07.27 |