2017-01-23 101 views
8

我發現這個method chaining in python,但即使是我無法理解的Python方法鏈接。基本方法鏈接

這裏的目標有兩個:解決編碼問題和理解方法鏈接(因爲我仍然有信心可調用不是100%)。

下到問題的定義。

我想要有兩個方法的類:一個設置對象=「線」和其它重寫爲「杆」的參數。

這是我走到這一步:

class foo(): 
    def __init__(self, kind=None): 
     self.kind = kind 

    def __call__(self, kind=None): 
     return foo(kind=kind) 

    def my_print(self): 
     print (self.kind) 

    def line(self): 
     return self(kind='line') 
    def bar(self): 
     return self(kind='bar') 

可悲的是,有了這個代碼,我可以實現我的目標,這樣做

a = foo() 
a.bar().line().bar().bar().line().my_print() 

但我想通過寫這封信,獲得相同的結果代碼

a = foo() 
a.bar.line.bar.bar.line.my_print() 

我該如何做到這一點?我想如何定義__call__方法是錯誤的。在此先感謝您的幫助。

回答

18

方法鏈僅僅是能夠增加.second_func()到任何.first_func()回報。確保所有可鏈接方法返回self相當容易實現。 (請注意,這與__call()__無關)。

class foo(): 
    def __init__(self, kind=None): 
     self.kind = kind 
    def my_print(self): 
     print (self.kind) 
     return self 
    def line(self): 
     self.kind = 'line' 
     return self 
    def bar(self): 
     self.kind='bar' 
     return self 

你可以忽略他們的返回值非鏈接方式使用foo對象:

a = foo() 
a.line() 
a.my_print() 
a.bar() 
a.my_print() 

assert a.kind == 'bar' 

或者,因爲每個函數現在返回對象本身,您可以在返回的直接操作 值。您可以使用方法鏈與此等價代碼:

b = foo() 
b.line().my_print().bar().my_print() 
assert b.kind == 'bar' 

甚至:

c = foo().line().my_print().bar().my_print() 
assert c.kind == 'bar' 

的擺脫()調用語法的問題是完全獨立的概念從方法鏈接。如果你想鏈屬性,並讓這些屬性改變它們的對象,使用@property裝飾器。 (但是,通過屬性變異的對象,似乎危險的最好使用方法,並用一個動詞命名爲:。.set_line()而不是.line,例如)

class foo(): 
    def __init__(self, kind=None): 
     self.kind = kind 
    def my_print(self): 
     print (self.kind) 
     return self 
    @property 
    def line(self): 
     self.kind = 'line' 
     return self 
    @property 
    def bar(self): 
     self.kind='bar' 
     return self 

a = foo() 
a.line 
a.my_print() 
a.bar 
a.my_print() 

assert a.kind == 'bar' 

b = foo() 
b.line.my_print().bar.my_print() 
assert b.kind == 'bar' 

c = foo().line.my_print().bar.my_print() 
assert c.kind == 'bar' 
+0

謝謝你的非常詳盡的回答! – Pezze

3

使用性質(描述)。

class foo: 
    def __init__(self, kind=None): 
     self.kind = kind 

    def __call__(self, kind=None): 
     return foo(kind=kind) 

    def my_print(self): 
     print (self.kind) 

    @property 
    def line(self): 
     return self(kind='line') 

    @property 
    def bar(self): 
     return self(kind='bar') 

但是,請注意,您不覆蓋任何內容,修改不會在原位(這可以說是很好,順便說一句)。無論如何,對於大多數現實世界的案例來說,這看起來並不是一個好的設計選擇,因爲在某些時候你的方法需要參數。