अजगर में ब्लॉक गुंजाइश


93

जब आप अन्य भाषाओं में कोड करते हैं, तो आप कभी-कभी ब्लॉक स्कोप बनाएंगे, जैसे:

statement
...
statement
{
    statement
    ...
    statement
}
statement
...
statement

एक उद्देश्य (कई का) कोड पठनीयता में सुधार करना है: यह दिखाने के लिए कि कुछ कथन एक तार्किक इकाई बनाते हैं या उस ब्लॉक में केवल कुछ स्थानीय चर का उपयोग किया जाता है।

क्या पायथन में एक ही काम करने का एक मुहावरेदार तरीका है?


2
One purpose (of many) is to improve code readability- पायथन कोड, सही तरीके से लिखा गया है (यानी, अजगर के ज़ेन का अनुसरण करते हुए ) पठनीय होने के लिए इस तरह के गार्निश की आवश्यकता नहीं होगी। वास्तव में, यह पायथन के बारे में मुझे पसंद है (कई) चीजों में से एक है।
बुरहान खालिद

मैंने बदलने __exit__और withबयान देने की कोशिश की है , globals()लेकिन मैं असफल रहा।
रग्गरो तुर्रा

1
परिवर्तनीय जीवनकाल को परिभाषित करने के लिए यह बहुत उपयोगी होगा, संसाधन अधिग्रहण से जुड़ा
रगरो तुर्रा

25
@BurhanKhalid: यह सच नहीं है। अजगर का ज़ेन आपको एक अस्थायी चर के साथ एक स्थानीय गुंजाइश को प्रदूषित करने से नहीं रोकता है। यदि आप एक एकल अस्थायी चर के प्रत्येक उपयोग को उदा। एक नेस्टेड फ़ंक्शन को परिभाषित करते हैं जिसे तुरंत कहा जाता है, तो पायथन का ज़ेन भी खुश नहीं होगा। स्पष्ट रूप से एक चर के दायरे को सीमित है पठनीयता में सुधार करने के लिए उपकरण है, क्योंकि यह सीधे जवाब देती है "इन पहचानकर्ता नीचे उपयोग किया जाता है?" - एक सवाल जो सबसे सुंदर पायथन कोड को पढ़ने को भी पैदा कर सकता है।
bluenote10

18
@BurhanKhalid फीचर न होना ठीक है। लेकिन यह कहना कि "ज़ेन" सिर्फ घृणित है।
फिल

जवाबों:


81

नहीं, ब्लॉक स्कोप बनाने के लिए कोई भाषा समर्थन नहीं है।

निम्नलिखित निर्माण कार्यक्षेत्र बनाते हैं:

  • मापांक
  • कक्षा
  • समारोह (इंकलाब लंबोदर)
  • जनरेटर अभिव्यक्ति
  • बोध (तानाशाही, सेट, सूची (पायथन 3.x में))

38

पायथन में मुहावरेदार तरीका है अपने कार्यों को छोटा रखना। यदि आपको लगता है कि आपको इसकी आवश्यकता है, तो अपने कोड को रिफलेक्टर करें! :)

पाइथन प्रत्येक मॉड्यूल, क्लास, फंक्शन, जनरेटर एक्सप्रेशन, डिफेंस कॉम्प्रिहेंशन, सेट कॉम्प्रिहेंशन और पायथन 3.x में भी प्रत्येक लिस्ट कॉम्प्रिहेंशन के लिए एक नया स्कोप बनाता है। इनके अलावा, फ़ंक्शन के अंदर कोई नेस्टेड स्कोप नहीं हैं।


12
"प्रोग्रामिंग में सबसे महत्वपूर्ण चीज किसी चीज को एक नाम देने की क्षमता है। दूसरी सबसे महत्वपूर्ण बात यह है कि किसी चीज को कुछ नाम देने की आवश्यकता नहीं है।" अधिकांश भाग के लिए, पायथन को यह आवश्यक है कि स्कोप (चर, आदि के लिए) को नाम दिया जाए। इस संबंध में, पायथन दूसरा सबसे महत्वपूर्ण परीक्षण करता है।
क्रेजी गेलव

19
प्रोग्रामिंग में सबसे महत्वपूर्ण चीजें आपके आवेदन की निर्भरता को प्रबंधित करने और कोड ब्लॉक के स्कोप का प्रबंधन करने की क्षमता है। अनाम ब्लॉक आपको कॉलबैक के जीवनकाल को सीमित करने देते हैं, जबकि अन्यथा, आपके कॉलबैक केवल एक बार उपयोग किए जाते हैं, लेकिन कार्यक्रम की अवधि के लिए रहते हैं, इससे वैश्विक गुंजाइश अव्यवस्था होती है और कोड की पठनीयता को नुकसान पहुंचाती है।
दिमित्री

मैंने अभी देखा है कि चर भी स्थानीय से लेकर तानाशाही तक हैं। मैंने पायथन 2.7 और 3.3 की कोशिश की, लेकिन मुझे यकीन नहीं है कि यह संस्करण पर निर्भर है।
वेजेंड्रिया

1
@wjandrea आप सही हैं - सूची में जोड़ा गया। इन के लिए पायथन संस्करणों के बीच कोई अंतर नहीं होना चाहिए।
स्वेन मार्नाच

4
मैं अंतिम वाक्य को फिर से शब्द दूंगा, क्योंकि आप बहुत अच्छी तरह से कार्यों के भीतर कार्य कर सकते हैं। तो फ़ंक्शन के अंदर नेस्टेड स्कोप हैं।
थॉमस एचएच

18

आप पायथन में सी ++ ब्लॉक स्कोप के समान कुछ कर सकते हैं अपने फ़ंक्शन के अंदर एक फ़ंक्शन घोषित करके और फिर तुरंत इसे कॉल कर सकते हैं। उदाहरण के लिए:

def my_func():
    shared_variable = calculate_thing()

    def do_first_thing():
        ... = shared_variable
    do_first_thing()

    def do_second_thing():
        foo(shared_variable)
        ...
    do_second_thing()

यदि आप सुनिश्चित नहीं हैं कि आप ऐसा क्यों करना चाहते हैं तो यह वीडियो आपको समझा सकता है।

मूल सिद्धांत किसी भी 'कचरा' (अतिरिक्त प्रकार / कार्य) को व्यापक दायरे में लाने के बिना हर चीज को यथासंभव कसौटी पर do_first_thing()कसना है। कॉलिंग फ़ंक्शन।


यह भी है कि Google डेवलपर्स द्वारा TensorFlow ट्यूटोरियल्स में उपयोग किया जा रहा है, जैसा कि यहाँ
Nino Filiu

13

मैं मानता हूं कि कोई ब्लॉक स्कोप नहीं है। लेकिन अजगर 3 में एक जगह इसे SEEM बनाता है जैसे कि इसमें ब्लॉक स्कोप है।

क्या हुआ जिसने यह रूप दिया? यह अजगर 2 में ठीक से काम कर रहा था। लेकिन अजगर 3 में परिवर्तनशील रिसाव को रोकने के लिए उन्होंने यह चाल चली है और यह परिवर्तन इस तरह दिखता है जैसे कि यह यहाँ ब्लॉक गुंजाइश है।

मुझे समझाने दो।


स्कोप के विचार के अनुसार, जब हम समान स्कोप के अंदर समान नामों के साथ वैरिएबल पेश करते हैं, तो इसका मान संशोधित किया जाना चाहिए।

यही अजगर 2 में हो रहा है

>>> x = 'OLD'
>>> sample = [x for x in 'NEW']
>>> x
'W'

लेकिन अजगर 3 में, भले ही एक ही नाम वाला चर पेश किया गया हो, यह ओवरराइड नहीं करता है, सूची की समझ किसी कारण से सैंडबॉक्स की तरह काम करती है और ऐसा लगता है कि इसमें एक नया स्कोप बना है।

>>> x = 'OLD'
>>> sample = [x for x in 'NEW']
>>> x
'OLD'

और यह उत्तर उत्तरदाता @ थॉमस के कथन के विरुद्ध जाता है। कार्यक्षेत्र, वर्ग या मॉड्यूल बनाने का एकमात्र साधन है क्योंकि यह एक नया क्षेत्र बनाने की एक अन्य जगह जैसा दिखता है।


0

मॉड्यूल (और पैकेज) आपके प्रोग्राम को अलग-अलग नामस्थानों में विभाजित करने का एक शानदार पायथोनिक तरीका है, जो इस प्रश्न का एक निहित लक्ष्य प्रतीत होता है। वास्तव में, जैसा कि मैं पायथन की मूल बातें सीख रहा था, मैंने ब्लॉक स्कोप फीचर की कमी से निराश महसूस किया। हालांकि एक बार जब मैंने पायथन मॉड्यूल को समझ लिया, तो मैं ब्लॉक स्कोप की आवश्यकता के बिना अपने पिछले लक्ष्यों को अधिक सुरुचिपूर्ण ढंग से महसूस कर सकता था।

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

कक्षाओं के साथ ब्लॉक गुंजाइश का प्रयास

कुछ क्षणों के लिए मुझे लगा कि मैंने कक्षा घोषणा के अंदर कोड चिपका कर ब्लॉक गुंजाइश हासिल कर ली है:

x = 5
class BlockScopeAttempt:
    x = 10
    print(x) # Output: 10
print(x) # Output: 5

जब कोई फ़ंक्शन परिभाषित होता है, तो दुर्भाग्य से यह टूट जाता है:

x = 5 
class BlockScopeAttempt: 
    x = 10
    print(x) # Output: 10
    def printx2(): 
        print(x) 
    printx2() # Output: 5!!!

ऐसा इसलिए है क्योंकि एक वर्ग के भीतर परिभाषित कार्य वैश्विक दायरे का उपयोग करते हैं। इसे ठीक करने का सबसे आसान (यद्यपि एकमात्र नहीं) तरीका स्पष्ट रूप से वर्ग को निर्दिष्ट करना है:

x = 5 
class BlockScopeAttempt: 
    x = 10
    print(x) # Output: 10
    def printx2(): 
        print(BlockScopeAttempt.x)  # Added class name
    printx2() # Output: 10

यह इतना सुरुचिपूर्ण नहीं है क्योंकि किसी वर्ग में निहित होने या न होने के आधार पर किसी को अलग से फ़ंक्शन लिखना होगा।

पायथन मॉड्यूल के साथ बेहतर परिणाम

मॉड्यूल स्थिर कक्षाओं के समान हैं, लेकिन मेरे अनुभव में मॉड्यूल बहुत साफ हैं। मॉड्यूल के साथ भी ऐसा करने के लिए, मैं my_module.pyनिम्नलिखित सामग्रियों के साथ वर्तमान कार्य निर्देशिका में एक फ़ाइल बनाता हूं :

x = 10
print(x) # (A)

def printx():
    global x
    print(x) # (B)

फिर मेरी मुख्य फ़ाइल या इंटरेक्टिव (जैसे ज्यूपिटर) सत्र में, मैं करता हूं

x = 5
import my_module # Output: 10 from (A)
my_module.printx() # Output: 10 from (B)
print(x) # Output: 5

स्पष्टीकरण के रूप में, प्रत्येक पायथन फ़ाइल एक मॉड्यूल को परिभाषित करता है जिसका अपना वैश्विक नाम स्थान है। एक मॉड्यूल आयात करने से आप इस नाम स्थान के चर को .सिंटैक्स के साथ एक्सेस कर सकते हैं ।

यदि आप एक इंटरैक्टिव सत्र में मॉड्यूल के साथ काम कर रहे हैं, तो आप शुरुआत में इन दो पंक्तियों को निष्पादित कर सकते हैं

%load_ext autoreload
%autoreload 2

और जब उनकी संबंधित फाइलें संशोधित हो जाएंगी और मॉड्यूल अपने आप लोड हो जाएंगे।

डेटा लोड करने और फ़िल्टर करने के लिए पैकेज

पैकेज का विचार मॉड्यूल अवधारणा का एक मामूली विस्तार है। एक पैकेज एक निर्देशिका (संभवतः रिक्त) __init__.pyफ़ाइल है, जिसे आयात पर निष्पादित किया जाता है। इस निर्देशिका के भीतर मॉड्यूल / पैकेज को .सिंटैक्स के साथ एक्सेस किया जा सकता है ।

डेटा विश्लेषण के लिए, मुझे अक्सर एक बड़ी डेटा फ़ाइल पढ़ने की आवश्यकता होती है और फिर विभिन्न फिल्टर को अंतःक्रियात्मक रूप से लागू करना होता है। किसी फ़ाइल को पढ़ने में कई मिनट लगते हैं, इसलिए मैं केवल एक बार करना चाहता हूं। ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग के बारे में मैंने स्कूल में जो सीखा, उसके आधार पर, मैं मानता था कि किसी वर्ग में तरीकों के रूप में फ़िल्टर करने और लोड करने के लिए कोड लिखना चाहिए। इस दृष्टिकोण का एक बड़ा नुकसान यह है कि अगर मैं अपने फिल्टर को फिर से परिभाषित करता हूं, तो मेरी कक्षा की परिभाषा बदल जाती है, इसलिए मुझे डेटा सहित पूरी कक्षा को फिर से लोड करना होगा।

आजकल पायथन के साथ, मैं एक पैकेज को परिभाषित करता हूं, my_dataजिसमें सबमोड्यूल्स होता है जिसका नाम loadऔर है filter। अंदर filter.pyमैं एक रिश्तेदार आयात कर सकते हैं:

from .load import raw_data

यदि मैं संशोधित करता हूं filter.py, तो autoreloadपरिवर्तनों का पता लगाएगा। यह पुनः लोड नहीं करता है load.py, इसलिए मुझे अपना डेटा पुनः लोड करने की आवश्यकता नहीं है। इस तरह मैं एक ज्यूपिटर नोटबुक में अपने फ़िल्टरिंग कोड को प्रोटोटाइप कर सकता हूं, इसे फ़ंक्शन के रूप में लपेट सकता हूं, और फिर सीधे मेरी नोटबुक से कट-पेस्ट कर सकता हूं filter.py। यह पता लगाने ने मेरे वर्कफ़्लो में क्रांति ला दी, और मुझे एक संदेहवादी से "ज़ेन के पायथन" में एक आस्तिक में बदल दिया।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.