2017-05-18 59 views
0

我想創建兩個對象,以便其他對象的某些對象的方法會重複。然後我嘗試這樣做:同類對象的重複方法

def backup(method): 
    def wrapper(self, *args, **kwargs): 
     method(self, *args, **kwargs) 
     getattr(self.another_tester, method.__name__)(*args, **kwargs) 
    return wrapper 

class Tester(): 
    def __init__(self, name): 
     self.name = name 
    def select_backup(self, tester): 
     self.another_tester = tester 
    @backup 
    def foo1(self, stop=False): 
     print("I am tester {}, do method foo1".format(self.name)) 
    @backup 
    def foo2(self, stop=False): 
     print("I am tester {}, do method foo2".format(self.name)) 
    @backup 
    def foo3(self, stop=False): 
     print("I am tester {}, do method foo3".format(self.name)) 

tester1 = Tester("A") 
tester2 = Tester("B") 
tester1.select_backup(tester2) 
tester2.select_backup(tester1) 
tester1.foo1() 
tester2.foo2() 
tester1.foo3() 

對於這樣的代碼我得到RuntimeError: maximum recursion depth exceeded while calling a Python object。類Tester有很多不同的方法(foo1,foo2,foo3,...),我想backup(重複)每種方法。所以我使用裝飾器。

我可以改變裝飾:

def backup(method): 
    def wrapper(self, *args, **kwargs): 
     method(self, *args, **kwargs) 
     try: 
      kwargs["stop"] 
     except KeyError: 
      getattr(self.another_tester, method.__name__)(stop=True, *args, **kwargs) 
    return wrapper 

它的工作,但我認爲還有更多的Python的方式來做到這一點。任何人都可以提供這種方式

+0

什麼,如果有一個較長的循環所需的行爲?它應該只有一個深度,還是應該持續到重複?就像,如果你有A,B和C,A代表B代表C代表A代表A代表? – mwchase

+0

不,它應該只是程序中類Tester的兩個對象。所以A代表B和B的代表到A.所以A是B的備份,而B是A的備份。 – nik

+0

請用一個解釋這個_ **的檢驗來更新你的問題。我們假設會有很多方法被重複,所以需要裝飾者** _ – stovfl

回答

0

如果你的一對對象總是同一類的實例(或者至少從未有不同的裝飾方法實現),你可以改變裝飾器,直接調用另一個實例上的原始方法,而是不是通過getattr獲得裝飾版本:

def backup(method): 
    def wrapper(self, *args, **kwargs): 
     method(self, *args, **kwargs) 
     method(self.another_tester, *args, **kwargs) 
    return wrapper 

如果你想能夠支持對不同類(和不同的方法實現)的對象,事情需要更復雜一些。您可以到原來的未修飾的方法的引用保存爲在包裝功能的屬性,然後看它當你需要它:

def backup(method): 
    def wrapper(self, *args, **kwargs): 
     method(self, *args, **kwargs) 
     other_method = getattr(self.another_tester, method.__name__).orig_method 
     other_method(self.another_tester, *args, **kwargs) 
    wrapper.orig_method = method 
    return wrapper