2012-08-29 11 views
18

में चेनिंग (itertools.chain साथ भ्रमित होने की नहीं)विधि अजगर

मैं निम्नलिखित पढ़ रहा था: http://en.wikipedia.org/wiki/Method_chaining

मेरा प्रश्न है: अजगर में विधि श्रृंखलन लागू करने के लिए सबसे अच्छा तरीका क्या है? यदि बुला method(*args)self.o को संशोधित करता है लेकिन None वापस नहीं करता है

class chain(): 
    def __init__(self, my_object): 
     self.o = my_object 

    def __getattr__(self, attr): 
     x = getattr(self.o, attr) 
     if hasattr(x, '__call__'): 
      method = x 
      return lambda *args: self if method(*args) is None else method(*args) 
     else: 
      prop = x 
      return prop 

list_ = chain([1, 2, 3, 0]) 
print list_.extend([9, 5]).sort().reverse() 

""" 
C:\Python27\python.exe C:/Users/Robert/PycharmProjects/contests/sof.py 
[9, 5, 3, 2, 1, 0] 
""" 

एक समस्या है:

यहाँ मेरी प्रयास है। (तो मुझे self वापस करना चाहिए या method(*args) रिटर्न वापस करना चाहिए)।

क्या किसी के पास चेनिंग लागू करने के बेहतर तरीके हैं? ऐसा करने के लिए शायद कई तरीके हैं।

क्या मुझे लगता है कि एक विधि हमेशा None लौटाती है तो मैं हमेशा self.o वापस कर सकता हूं?

+0

(नोट मुझे यकीन नहीं है कि पाइथन में विधि श्रृंखला का उपयोग किया जाना चाहिए, लेकिन मुझे अभी भी दिलचस्पी है) –

+0

आपको [शुद्ध फ़ंक्शंस] (http://en.wikipedia.org/wiki/Pure_function) का उपयोग करना चाहिए ताकि वह विधियां 'self.o' को सीधे संशोधित नहीं करती हैं, बल्कि इसके बजाय संशोधित संस्करण लौटाती हैं। साथ ही, '__getattr__' को एक श्रृंखला उदाहरण वापस करना चाहिए। – reubano

उत्तर

16

एक बहुत ही रोचक Pipe लाइब्रेरी है जो आपके प्रश्न का उत्तर हो सकती है। उदाहरण :: के लिए

seq = fib() | take_while(lambda x: x < 1000000) \ 
      | where(lambda x: x % 2) \ 
      | select(lambda x: x * x) \ 
      | sum() 
+2

+1 सी # के LINQ में उपयोग करने के बाद, पाइथन में पहली बार आयात करने वाली पाइप 'है। (आपको 'पाइप आयात * से' के साथ सावधान रहना होगा) – Kos

+4

वैसे भी, 'पाइप' कार्यों को लिखने के लिए है - फ़ंक्शन ए के परिणाम को फ़ंक्शन बी के लिए तर्क के रूप में पास करना। चेनिंग (आमतौर पर) उसी ऑब्जेक्ट को वापस करने के बारे में है एक श्रृंखला में कई संशोधन करने के लिए कई कॉल। JQuery ने बहुत लोकप्रिय किया है। – Kos

+1

सच है। लेकिन मेरा मानना ​​है कि चेनिंग को पाइथन में इस्तेमाल नहीं किया जाना चाहिए जिस तरह से इसका उपयोग जावास्क्रिप्ट में किया जाता है। –

4

किसी ऑब्जेक्ट की किसी भी विधि को जंजीर करने की इजाजत देने का कोई सामान्य तरीका नहीं होने वाला है, क्योंकि आप नहीं जानते कि विधि किस तरह का मूल्य लौटाती है और क्यों नहीं कि यह विशेष विधि कैसे काम करती है। किसी भी कारण से None वापस कर सकते हैं; इसका मतलब यह नहीं है कि विधि ने वस्तु को संशोधित किया है। इसी तरह, वे विधियां जो एक मूल्य वापस करती हैं, वे अभी भी एक मूल्य वापस नहीं कर सकते हैं जिसे जंजीर बनाया जा सकता है। list.index: fakeList.index(1).sort() जैसी विधि को श्रृंखलाबद्ध करने का कोई तरीका नहीं है, काम करने की अधिक उम्मीद नहीं हो सकती है, क्योंकि index का पूरा बिंदु यह एक संख्या देता है, और उस संख्या का मतलब कुछ है, और मूल पर श्रृंखला के लिए अनदेखा नहीं किया जा सकता वस्तु।

यदि आप पाइथन के बिल्टिन प्रकारों के साथ कुछ विशिष्ट तरीकों (जैसे सॉर्ट और निकालने) को श्रृंखलाबद्ध करने के लिए बस झुका रहे हैं, तो आप उन विशेष तरीकों को स्पष्ट रूप से लपेटकर बेहतर कर सकते हैं (उन्हें अपने रैपर वर्ग में ओवरराइड करके) __getattr__ के साथ एक सामान्य तंत्र करने की कोशिश कर रहा है।

+0

धन्यवाद - आप सही हैं। मुझे नहीं लगता था कि यह सामान्य होना संभव था।सबसे अच्छा मैं सोच सकता हूं कि प्रोग्रामर को यह तय करना है कि वे चेन करना चाहते हैं या नहीं। E.G. डिफ़ॉल्ट रूप से यह स्वयं को वापस नहीं करता है (यह केवल विधि देता है कि विधि क्या देता है) लेकिन यदि प्रोग्रामर स्पष्ट रूप से list_.chain.sort() गया तो यह किसी के बजाय list_ वापस कर सकता है। –

+3

@robertking: ठीक है, सामान्य सौदा यह है कि विधि चेनिंग ऐसा कुछ नहीं है जिसे आप आसानी से मौजूदा वस्तुओं पर ले जा सकते हैं। आपको मूल रूप से काम करने के लिए विधि को चेन करने के साथ एक वर्ग को डिजाइन करना होगा। – BrenBarn

13

यह इतना है कि तरीकों self.data सीधे संशोधित नहीं है, लेकिन बजाय संशोधित संस्करण वापसी अगर आप केवल pure functions का उपयोग संभव है। आपको Chainable उदाहरण वापस लौटना होगा।

यहाँ सूचियों के साथ collection pipelining का उपयोग कर एक उदाहरण है:

import itertools 

try: 
    import builtins 
except ImportError: 
    import __builtin__ as builtins 


class Chainable(object): 
    def __init__(self, data, method=None): 
     self.data = data 
     self.method = method 

    def __getattr__(self, name): 
     try: 
      method = getattr(self.data, name) 
     except AttributeError: 
      try: 
       method = getattr(builtins, name) 
      except AttributeError: 
       method = getattr(itertools, name) 

     return Chainable(self.data, method) 

    def __call__(self, *args, **kwargs): 
     try: 
      return Chainable(list(self.method(self.data, *args, **kwargs))) 
     except TypeError: 
      return Chainable(list(self.method(args[0], self.data, **kwargs))) 

इस तरह यह प्रयोग करें:

chainable_list = Chainable([3, 1, 2, 0]) 
(chainable_list 
    .chain([11,8,6,7,9,4,5]) 
    .sorted() 
    .reversed() 
    .ifilter(lambda x: x%2) 
    .islice(3) 
    .data) 
>> [11, 9, 7] 

ध्यान दें कि .chainitertools.chain को संदर्भित करता है और न ओपी के chain