2011-01-31 16 views
68

मैं निम्नलिखित कोड एक समारोह के अंदर है:अजगर बंद: माता-पिता दायरे में चर करने के लिए लिखें

stored_blocks = {} 
def replace_blocks(m): 
    block = m.group(0) 
    block_hash = sha1(block) 
    stored_blocks[block_hash] = block 
    return '{{{%s}}}' % block_hash 

num_converted = 0 
def convert_variables(m): 
    name = m.group(1) 
    num_converted += 1 
    return '<%%= %s %%>' % name 

fixed = MATCH_DECLARE_NEW.sub('', template) 
fixed = MATCH_PYTHON_BLOCK.sub(replace_blocks, fixed) 
fixed = MATCH_FORMAT.sub(convert_variables, fixed) 

तत्वों को जोड़ने stored_blocks को ठीक काम करता है, लेकिन मैं दूसरे subfunction में num_converted में वृद्धि नहीं कर सकते हैं:

UnboundLocalError: local variable 'num_converted' referenced before assignment

मैं global का उपयोग कर सकता हूं लेकिन वैश्विक चर बदसूरत हैं और मुझे वास्तव में उस चर को वैश्विक होने की आवश्यकता नहीं है।

तो मैं उत्सुक हूं कि मैं पैरेंट फ़ंक्शन के दायरे में एक चर को कैसे लिख सकता हूं। nonlocal num_converted शायद नौकरी करेगा, लेकिन मुझे एक समाधान की आवश्यकता है जो पायथन 2.x के साथ काम करता है।

+4

कुछ हद तक लोकप्रिय विश्वास (इस तरह के प्रश्नों के आधार पर निर्णय) के विपरीत 'def' एकमात्र कीवर्ड नहीं है जो नामस्थान को परिभाषित करता है:' वर्ग 'भी है। 2.12 कामों में –

उत्तर

71

समस्या:।। इसका कारण यह है पायथन के scoping नियम पागल हैं की उपस्थिति += असाइनमेंट ऑपरेटर लक्ष्य को चिह्नित करता है, num_converted, जो कि संलग्न कार्यक्षेत्र के क्षेत्र में स्थानीय है, और वहां से केवल एक स्कोपिंग स्तर तक पहुंचने के लिए पायथन 2.x में कोई अच्छा तरीका नहीं है। केवल global कीवर्ड परिवर्तनीय संदर्भों को उठा सकता है वर्तमान दायरा, और यह आपको सीधे शीर्ष पर ले जाता है।

फिक्स:num_converted को एकल-तत्व सरणी में बदलें।

num_converted = [0] 
def convert_variables(m): 
    name = m.group(1) 
    num_converted[0] += 1 
    return '<%%= %s %%>' % name 
+6

क्या आप समझा सकते हैं कि यह क्यों जरूरी है? मैं काम करने के लिए कोड ओपी करने की उम्मीद की होगी। –

+36

क्योंकि पाइथन के स्कोपिंग नियम डिमेंटेड हैं। '+ =' असाइनमेंट ऑपरेटर की उपस्थिति लक्ष्य को चिह्नित करती है, 'num_converted', जो कि संलग्न कार्यक्षेत्र के क्षेत्र में स्थानीय है, और वहां से केवल एक स्कोपिंग स्तर तक पहुंचने के लिए पायथन 2.x में कोई अच्छा तरीका नहीं है। केवल 'वैश्विक' कीवर्ड मौजूदा दायरे से परिवर्तनीय संदर्भ उठा सकता है, और यह आपको सीधे शीर्ष पर ले जाता है। –

+0

मैंने उस दृष्टिकोण का उपयोग किया है और यह ठीक काम करता है। – ThiefMaster

9

global कीवर्ड का उपयोग करना ठीक है। यदि आप लिखना:

num_converted = 0 
def convert_variables(m): 
    global num_converted 
    name = m.group(1) 
    num_converted += 1 
    return '<%%= %s %%>' % name 

... num_converted "वैश्विक चर" (यानी यह नहीं दिखाई किसी अन्य अप्रत्याशित स्थानों में हो जाता है) नहीं बन जाता है, यह सिर्फ यह convert_variables अंदर संशोधित किया जा सकता है। ऐसा लगता है कि आप वास्तव में क्या चाहते हैं।

इसे एक और तरीका रखने के लिए, num_convertedपहले से ही एक वैश्विक चर है। सभी global num_converted वाक्य रचना करता अजगर बता "इस समारोह के अंदर, एक स्थानीय num_converted चर, मौजूदा वैश्विक एक का निर्माण नहीं करतीं बजाय, का उपयोग है

+3

'ग्लोबल' काफी काम करता है कि कैसे 'nonlocal' 3.x में करता है। –

+2

"इसे एक और तरीका रखने के लिए, num_converted पहले से ही एक वैश्विक चर है" - मेरा कोड फ़ंक्शन के अंदर चल रहा है .. इसलिए यह वर्तमान में वैश्विक नहीं है। – ThiefMaster

+2

आह, मैंने "फ़ंक्शन के अंदर" भाग पर ध्यान नहीं दिया था, माफ करना - उस मामले में, मार्सेलो की लंबाई-एक-सूची एक बेहतर (लेकिन बदसूरत) समाधान हो सकती है। – Emile

6

राज्य को पकड़ने के लिए कक्षा के उदाहरण का उपयोग करने के बारे में क्या? आप एक वर्ग का दृष्टांत और बाद के चरणों के लिए उदाहरण के तरीकों गुजरती हैं और उन कार्यों स्वयं के लिए एक संदर्भ के लिए होता है ...

+7

थोड़ा अधिक ओवरकिलीश और जावा प्रोग्रामर से आने वाले समाधान की तरह लगता है। ; पी – ThiefMaster

+1

हे, लेकिन यह साफ है! ;) – Seb

+1

@ थिफमास्टर यह ओवरकिल क्यों है? यदि आप माता-पिता के दायरे तक पहुंच चाहते हैं तो आपको ** ** पायथन में कक्षा का उपयोग करना चाहिए। – schlamar

25

(संपादित जवाब के लिए नीचे देखें)

आप की तरह कुछ का उपयोग कर सकते हैं:

def convert_variables(m): 
    name = m.group(1) 
    convert_variables.num_converted += 1 
    return '<%%= %s %%>' % name 

convert_variables.num_converted = 0 

इस तरह, convert_variable विधि का एक सी की तरह "स्थिर" चर के रूप में काम करता है num_converted


(संपादित)

def convert_variables(m): 
    name = m.group(1) 
    convert_variables.num_converted = convert_variables.__dict__.get("num_converted", 0) + 1 
    return '<%%= %s %%>' % name 

इस तरह, आपको मुख्य प्रक्रिया में काउंटर को प्रारंभ करने की आवश्यकता नहीं है।

+3

दाएं। और ध्यान दें कि आप _must_ विशेषता को कन्वर्ट करते हैं 'convert_variables.num_converted' _after_ फ़ंक्शन को परिभाषित करते हैं, हालांकि ऐसा करने में अजीब लग रहा है। –

+0

@PabloG 3.x में nonlocal के अलावा, इस प्रश्न का सबसे संतोषजनक उत्तर; परिवर्तनीय प्रकार का उपयोग [] सस्ते कामकाज है। – user2290820

6

मेरे पास कुछ टिप्पणियां हैं।

सबसे पहले, कच्चे कॉलबैक से निपटने के दौरान ऐसे घोंसले वाले कार्यों के लिए एक आवेदन आता है, जैसे xml.parsers.expat जैसे पुस्तकालयों में उपयोग किया जाता है। (लाइब्रेरी लेखकों ने इस दृष्टिकोण को चुना है, लेकिन आप इसका उपयोग करने के कारण हैं।)

दूसरा: कक्षा के भीतर, सरणी के लिए बहुत अच्छे विकल्प हैं (num_converted [0])। मुझे लगता है कि सेबस्तजन किस बारे में बात कर रहा था।

class MainClass: 
    _num_converted = 0 
    def outer_method(self): 
     def convert_variables(m): 
      name = m.group(1) 
      self._num_converted += 1 
      return '<%%= %s %%>' % name 

यह अभी भी काफी अजीब कोड ... में एक टिप्पणी की योग्यता के लिए है लेकिन चर वर्ग के लिए कम से कम स्थानीय है।

+0

अरे, स्टैक ओवरफ़्लो में आपका स्वागत है - लेकिन एक उत्तर के रूप में "टिप्पणी" पोस्ट करना वास्तव में ऐसा कुछ नहीं है जो आप यहां कर सकते हैं। हमारे पास इसके लिए टिप्पणियां हैं (हालांकि, आपको उन्हें पोस्ट करने के लिए कुछ प्रतिनिधि की आवश्यकता है - लेकिन जवाब पोस्ट न करें क्योंकि आपके पास अभी तक कोई टिप्पणी के लिए पर्याप्त प्रतिनिधि नहीं है) – ThiefMaster

+5

हाय, आपका भी स्वागत है! मुझे आपकी टिप्पणी, या आपके द्वारा उपयोग की जाने वाली कई शर्तों को समझ में नहीं आता है। और मैं व्यस्त व्यक्ति हूं, बस सहायक होने की कोशिश कर रहा हूं! –

+0

कोई समस्या नहीं - हालांकि http://stackoverflow.com/about पर एक नज़र डालें। सहायक होने के दौरान हमेशा पोस्ट की गई एक टिप्पणी की सराहना की जाती है जो अंततः हटा दी जाएगी चाहे कितना अच्छा हो। – ThiefMaster

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