2017-01-23 8 views
8

Bu method chaining in python numaralı belgeyi buldum, ancak Python'da zincirleme işlemini anlayamadım.Temel yöntem zincirleme

Burada hedefler iki: kodlama sorununu çöz ve yöntem zincirlemeyi anla ((hala% 100'lük callables ile güvenmem).

Sorun tanımına inersiniz.

İki yönteme sahip bir sınıf istiyorum: biri object = 'line' parametresini ve diğer 'over' yazısını 'bar' olarak ayarlar. ,

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') 

Ne yazık ki bu kod ile ben amacım bu

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

yapıyor elde edebilirsiniz Ama bu yazarak aynı sonucu elde etmek istiyorum:

Bu

Bugüne kadar ne var kod

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

Bunu nasıl başarırım? __call__ yöntemini nasıl tanımladığımda yanlış bir şey olduğunu düşünüyorum. Yardımlarınız için şimdiden teşekkür ederiz.

cevap

18

Yöntem zincirleme, .first_func() döndürme sayısına göre .second_func() ekleyebilmektir. Tüm zincirlenebilir yöntemlerin self'u iade etmesini sağlayarak oldukça kolay uygulanır. (Bunun __call()__ ile ilgisi olmadığını unutmayın).

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 

Onların dönen değerleri göz ardı ederek olmayan bir zincirleme şekilde foo nesneleri kullanabilirsiniz: her işlevi artık nesnenin kendisine döner beri, döndürülen doğrudan çalışabilir,

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

assert a.kind == 'bar' 

Ya değer. Bu eşdeğer koduyla yöntem zincirleme kullanabilirsiniz: hatta

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

Veya:

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

() çağıran sözdizimi kurtulmanın soru yöntemi zincirleme bir tamamen ayrı bir kavram olduğunu. Zincir özellikleri istiyorsanız ve bu özelliklerin nesnelerini değiştirdiyseniz, @property dekoratörünü kullanın. (Ama bir özellik aracılığıyla nesneleri mutasyona tehlikeli görünüyor iyi bir yöntem kullanmak ve bir fiil ile isim:.. Örneğin .set_line() yerine .line) çok ayrıntılı cevap için

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

Teşekkür !! – Pezze

3

Özelliklerini (açıklayıcılarını) kullanın.

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') 

Not olsa da, hiçbir şey üzerine olduğunu, modifikasyon (btw tartışmasız iyi olan) INPLACE çalışmaz. Her neyse, bu çoğu gerçek dünyadaki durumlar için iyi bir tasarım tercihi gibi görünmüyor, çünkü bir noktada yöntemleriniz argümanlar gerektirecektir.