2015-12-16 4 views
11

तो मैं निम्नलिखित शैली के प्रश्न पर अधिक अनुभवी पायथन प्रोग्रामर के विचारों के बारे में उत्सुक हूं। मान लीजिए कि मैं एक ऐसा फ़ंक्शन बना रहा हूं जो पंक्तियों को एक पांडा डेटाफ्रेम या किसी भी समान उपयोगकेस के माध्यम से पंक्ति में फिर से चलाने जा रहा है जहां फ़ंक्शन को इसके पिछले राज्य तक पहुंच की आवश्यकता होती है।पाइथन में मुहावरे: बंद बनाम फंक्टर बनाम ऑब्जेक्ट

1) क्लोजर:

def outer(): 
    previous_state = None 
    def inner(current_state) : 
     nonlocal previous_state 
     #do something 
     previous_state=current_state 
     return something 

तो अगर आप एक जावास्क्रिप्ट पृष्ठभूमि से आते हैं इस निस्संदेह आप के लिए प्राकृतिक लगेगा वहाँ अजगर में इस लागू करने के लिए कम से कम चार तरीके होने लगते हैं। यह पाइथन में भी बहुत स्वाभाविक लगता है, जब तक आपको संलग्न स्कोप तक पहुंचने की आवश्यकता न हो, तब तक जब आप inner.__code__.co_freevars जैसे कुछ कर लेंगे, जो आपको टुपल के रूप में आपके संलग्न चर के नाम देगा, और एक के सूचकांक को ढूंढने के लिए आप चाहते हैं, और उसके मूल्य प्राप्त करने के लिए inner.__closure__[index].cell_contents पर जा रहे हैं। बिल्कुल सुरुचिपूर्ण नहीं है, लेकिन मुझे लगता है कि बिंदु अक्सर गुंजाइश छिपाने के लिए होता है, इसलिए यह समझ में आता है कि इसे पहुंचना मुश्किल होना चाहिए। दूसरी ओर, यह थोड़ा अजीब लगता है कि पाइथन संलग्न कार्य को निजी बनाता है जब यह ओओपी भाषाओं की तुलना में एक निजी चर के लिए लगभग हर दूसरे तरीके से दूर हो जाता है।

2) functor

def outer(): 
    def inner(current_state): 
     #do something 
     inner.previous_state=current_state 
     return something 
    ret = inner 
    ret.previous_state=None 
    return ret 

यह है कि में "बंद खोलता है" अब enclosing राज्य समारोह की विशेषता के रूप पूरी तरह से दिख रहा है। यह काम करता है क्योंकि कार्य वास्तव में छिपाने में वस्तुएं हैं। मैं इस पर सबसे अधिक पाइथनिक के रूप में झुका रहा हूँ। इसका स्पष्ट, संक्षिप्त और पठनीय।

3) ऑब्जेक्ट्स यह शायद OOP प्रोग्रामर

class Calculator(Object) : 
    def __init__(self): 
     self.previous_state=None 

    def do_something(self, current_state) : 
     #do_something 
     self.previous_state = current_state 
     return something 

सर्वाधिक परिचित सबसे बड़ी चोर यहाँ है कि आप वर्ग परिभाषाओं की एक बहुत कुछ के साथ खत्म हो जाते है। जावा की तरह पूरी तरह से ओओपी भाषा में यह ठीक है, जहां आपके पास इंटरफेस हैं और इसे प्रबंधित करने की तरह है, लेकिन यह एक डकप्टेड भाषा में थोड़ी सी अजीब लगता है कि बहुत से सरल वर्गों को बस एक ऐसे कार्य के आसपास ले जाने के लिए थोड़ा सा राज्य चाहिए।

4) वैश्विक - मैं इस रूप में प्रदर्शित नहीं होगा मैं विशेष रूप से प्रदूषण वैश्विक नाम स्थान

5) डेकोरेटर से बचना चाहते हैं - यह एक Curveball का एक छोटा सा है, लेकिन आप आंशिक स्टोर करने के लिए उपयोग कर सकते हैं सज्जाकार राज्य की जानकारी

@outer 
def inner(previous_state, current_state): 
    #do something 
    return something 

def outer(inner) : 
    def wrapper(current_state) : 
     result = inner(wrapper.previous_state, current_state) 
     wrapper.previous_state = current_state 
     return result 
    ret = wrapper 
    ret.previous_state=None 
    return result 

वाक्य रचना इस प्रकार का मेरे लिए कम से कम परिचित है, लेकिन अगर मैं अब

func = inner 

फोन मैं वास्तव में

func = outer(inner) 

और फिर पाने के बार-बार func() कृत्यों बुला सिर्फ functor की तरह उदाहरण। मैं वास्तव में वास्तव में इस तरह से नफरत है। ऐसा लगता है कि मुझे वास्तव में गैर पारदर्शी वाक्यविन्यास होना है कि यह स्पष्ट नहीं है कि आंतरिक (current_state) को कई बार कॉल करने से आपको वही परिणाम मिलेगा या यदि यह आपको हर बार एक नया सजाया गया कार्य देगा, तो यह बुरा अभ्यास जैसा लगता है सजावटी बनाने के लिए जो इस तरह से एक समारोह में राज्य जोड़ते हैं।

तो कौन सा सही तरीका है? मैं यहां किस पेशेवर और विपक्ष से चूक गया हूं?

+1

मैं काफी नहीं हूं कि आपको लगता है कि आपको 'आंतरिक .__ बंद करने' के माध्यम से बंद-ओवर चर का उपयोग करने की आवश्यकता क्यों है; नाम केवल उस संरचना में समाप्त होते हैं क्योंकि आप सक्रिय रूप से इन्हें आंतरिक फ़ंक्शन * पहले से ही * में उपयोग कर रहे हैं। '__closure__' संरचना वास्तव में एक आंतरिक कार्यान्वयन विस्तार है। –

+0

मैं लोगों को इसे विकसित करने दूंगा, लेकिन अनुभव से, अजगर डेवलपर्स इस तरह के परिदृश्य के लिए कक्षा का उपयोग करते हैं। या सजावटी जब आपको पूर्ण स्पष्टता की आवश्यकता नहीं होती है और '@ 'के साथ अच्छा वाक्यविन्यास पसंद करते हैं। आप 'nonlocal' या' global' कीवर्ड का उपयोग नहीं करना चाहते हैं। और फंक्चर अक्सर बंद होने के लिए एपर्ट छोड़ दिया जाता है। – Cyrbil

+0

बंद-ओवर नाम इस संबंध में स्थानीय लोगों से अलग नहीं हैं; आप आम तौर पर अपने स्थानीय लोगों को पढ़ने के लिए एक समारोह में नहीं पहुंचते हैं, आप बंद होने के साथ एक ही चीज़ क्यों कर रहे हैं? यदि आपको उस स्थिति को फ़ंक्शन के बाहर उपयोग के लिए बेनकाब करने की आवश्यकता है, तो फ़ैक्टर या क्लास दृष्टिकोण का उपयोग करें। –

उत्तर

3

तो यह करने के लिए सही जवाब प्रतिदेय वस्तु है, जो अनिवार्य रूप से अजगर में बंद करने की मुहावरा बदल देता है।

तो परिवर्तन ऊपर विकल्प 3 बंद काम कर रहे:

class Calculator(Object) : 
    def __init__(self): 
     self.previous_state=None 

    def do_something(self, current_state) : 
     #do_something 
     self.previous_state = current_state 
     return something 

class Calculator(Object) : 
    def __init__(self): 
     self.previous_state=None 

    def __call__(self, current_state) : 
     #do_something 
     self.previous_state = current_state 
     return something 

लिए और अब आप इसे एक समारोह की तरह कह सकते हैं। तो

func = Calculator(): 
for x in list: 
    func(x) 
2

आप जनरेटर को परिभाषित कर सकते हैं, जो एक कॉप्रोसेस का एक प्रतिबंधित रूप है।

def make_gen(): 
    previous_state = None 
    for row in rows: 
     # do something 
     previous_state = current_state 
     yield something 

thing = make_gen() 
for item in thing: 
    # Each iteration, item is a different value 
    # "returned" by the yield statement in the generator 
इसके बजाय thing बुला (जो अपने भीतर के समारोह की जगह) बार-बार, तो आप इस पर पुनरावृति (जो मूल रूप से next(thing) बार-बार कॉल के समान है) के

राज्य पूरी तरह जनरेटर के शरीर के भीतर निहित है।

यदि आप वास्तव में इसे फिर से चालू नहीं करना चाहते हैं, तो आप अभी भी next पर कॉल करके कॉप्रोसेस को "पुनः दर्ज" कर सकते हैं।

thing = make_gen() 
first_item = next(thing) 
# do some stuff 
second_item = next(thing) 
# do more stuff 
third_item = next(thing) 
fourth_item = next(thing) 
# etc 
+0

यह सवाल से स्पष्ट नहीं है कि ओपी के कोड में इसका उपयोग कैसे किया जाएगा। मुझे संदेह है कि डेटा फ्रेम से पंक्तियों को 'make_gen'' के तर्क के रूप में पारित किया जाएगा (फिलहाल, मेरे पास कोई तर्क नहीं है, लेकिन लूप में मुक्त चर 'पंक्तियां' डेटाफ्रेम से होने का इरादा है)। – chepner

संबंधित मुद्दे