2011-07-04 4 views
2

처음에는 일을하려는 방식이 파이썬 적이라고 생각한다면 자유롭게 대안을 제안 할 수 있습니다.상속을 사용하지 않는 클래스 메서드 덮어 쓰기 (파이썬)

외부 이벤트를 기반으로 기능을 변경해야하는 개체가 있습니다. 내가 원래하고 있었던 것은 원본으로부터 상속받은 (새로운 객체를 OrigObject()이라고 부름) 객체를 만들고 변경하는 메소드를 덮어 씁니다 (새 객체 NewObject()이라고 부름). 그런 다음 두 생성자를 수정하여 전달 된 객체를 기반으로 자체 값을 채우기 위해 다른 유형의 완전한 객체를 가져올 수 있습니다. 그런 다음 기능을 변경해야 할 때 myObject = NewObject(myObject)을 실행하면됩니다.

이제는 이러한 접근 방식에 몇 가지 문제점이 나타나기 시작했습니다. 우선, 객체를 참조하는 다른 장소도 새로운 유형을 참조하도록 업데이트해야합니다 (예 : 위의 명령문은 로컬 myObject 변수 만 업데이트합니다). 하지만 업데이트하기가 어렵지 않습니다. 이상한 프로그램 동작을 방지하기 위해 개체를 변경할 때마다 성가신 부분을 다른 곳에서 업데이트하는 것을 기억하고 있습니다.

둘째, NewObject()에서 단일 메서드가 필요하지만 OrigObject()에서 다른 메서드가 필요하다는 것을 알았습니다. 그리고이 기능을 즉시 전환 할 수 있어야합니다. M * N 개의 다른 클래스를 만들 필요가있는 상속을 사용하는 것이 더 이상 최상의 솔루션처럼 보이지 않습니다 (여기서 M은 클래스가 변경할 수있는 메소드의 수이고 N은 변형의 수입니다). 각 메서드)에서 상속하는 OrigObject().

대신 속성 매핑을 사용하려고 생각했지만 문제가있는 것으로 보입니다. 예를 들어, 나는 이런 식으로 뭔가가 있다고 가정 :

def hybrid_type2(someobj, a): 
    #do something else 
    ... 

class OrigObject(object): 
    ... 
    def hybrid_fun(self, a): 
     #do something 
     ... 

    def switch(type): 
     if type == 1: 
      self.hybrid_fun = OrigObject.hybrid_fun 
     else: 
      self.fybrid_fun = hybrid_type2 

문제는,이 일을하고 전환 후 새로운 hybrid_fun 전화를 시도한 후, 나는 그 hybrid_type2()가 정확히 2 인수를 말하는 오류가 발생되어 있지만 그걸 하나 지나쳐. 객체 자체의 메소드처럼 새로운 객체의 인자로서 객체 자체가 더 이상 쓰이지 않는 것처럼 보입니다.

클래스 내에 hybrid_type2를 포함시킨 다음 self.hybrid_fun = self.hybrid_type2을 사용했지만 self.hybrid_fun = OrigObject.hybrid_fun을 사용하면 첫 번째 인수가 OrigObject 유형이어야한다고 불평하는 비슷한 오류가 발생합니다. 나는 대신 OrigObject.hybrid_fun() 로직을 OrigObject.hybrid_type1() 안에 정의 할 수 있다는 것을 알고 있습니다. 그래서 객체를 갖는 것을 피하기 위해 클래스에 상대적이 아닌 인스턴스에 상대적으로 설정하는 것과 같은 방식으로 되돌릴 수 있습니다. 그러나 나는 여기에서 볼 수없는 더 깨끗한 접근법이 있다면 여기에 묻고 싶다. 감사합니다.

EDIT : 감사합니다. 몇 가지 해결책을 찾았습니다. 필자는 types.MethodType()을 사용하는 전략 패턴을 사용하여 결국 파이썬에서 전략 패턴을 수행하는 방법을 설명하는 대답을 받아 들였습니다 (Wikipedia 기사는 더 일반적이었고 인터페이스 사용은 Python에서 필요하지 않습니다) .

+0

+1 창조적 인 접근 방식의 경우 – Predator

+0

클래스 수준에서 메서드를 할당해야합니다. 그러면 메서드 자체가 인수로 전달됩니다. (이미 같은 이름의 객체 레벨에 메서드가있는 경우 작동하지 않습니다.) - 또한 : "외부 이벤트를 기반으로 기능을 변경해야합니다." ? 우리는 더 나은 접근 방법을 제공 할 수있을 것입니다;) – phant0m

답변

3

는 특정 인스턴스에 대한 인스턴스 메서드를 만드는 유형 모듈을 사용합니다.

예 :

import types 

def strategyA(possible_self): 
    pass 

instance = OrigObject() 

instance.strategy = types.MethodType(strategyA, instance) 

instance.strategy() 

이 경우에만 영향을 주며 다른 인스턴스는 영향을 미치지 않습니다.

1

과 같이 그것을 정의에 대해 무엇 :

def hybrid_type2(someobj, a): 
    #do something else 
    ... 

def hybrid_type1(someobj, a): 
    #do something 
    ... 

class OrigObject(object): 

    def __init__(self): 
     ... 
     self.run_the_fun = hybrid_type1 

    ... 
    def hybrid_fun(self, a): 
     self.run_the_fun(self, a) 

    def type_switch(self, type): 
     if type == 1: 
      self.run_the_fun = hybrid_type1 
     else: 
      self.run_the_fun = hybrid_type2 
+0

메소드가 바인딩되지 않았으므로이 방법은 작동하지 않습니다. 'OrigObject.run_the_fun'에 메소드를 할당해야합니다. 그러면이 클래스의 모든 인스턴스의 동작이 변경됩니다. – phant0m

+0

@ phant0m [여기] (http://ideone.com/X9nMK)에서 일하는 것 같습니다. 바인딩 된/언 바운드 방식의 관점에서 작동하는 이유에 대한 미묘한 부분을 완전히 인식하지 못했습니다. 무슨 일이 일어나고있는 것은 self.run_the_fun이 단지 함수라는 변수로 취급된다는 것입니다. – trutheality

+0

아, 나는 그것을 실행할 수있는 특별한 방법이 있다는 것을 알지 못했습니다. 나는 당신이 그것을 호출하기를 원한다고 생각했다 :'orig_object.run_the_fun ("something")' – phant0m

2

파이썬에 대한 descriptors을 읽어보십시오.다음 코드는 작동합니다 :

else: 
    self.fybrid_fun = hybrid_type2.__get__(self, OrigObject) 
+0

이것이 어떻게 설명자가 되는가? – phant0m

+0

@ phant0m nope. 이 방법은 언 바운드 메소드입니다. –

+0

아, 그에게 설명자를 사용하길 원했다고 생각했습니다. 지금 무슨 뜻인지 알 겠어. 바운드 메소드로 만들고 싶습니다. 즉, None – phant0m

0

당신은 런타임에 클래스를 변경할 수 있습니다

class OrigObject(object): 
    ... 
    def hybrid_fun(self, a): 
     #do something 
     ... 
    def switch(self): 
     self.__class__ = DerivedObject 


class DerivedObject(OrigObject): 
    def hybrid_fun(self, a): 
     #do the other thing 
     ... 
    def switch(self): 
     self.__class__ = OrigObject