दूसरे मॉड्यूल से मॉड्यूल चर कैसे बदलें?


107

मान लीजिए कि मेरे पास एक पैकेज है bar, और इसमें शामिल हैं bar.py:

a = None

def foobar():
    print a

और __init__.py:

from bar import a, foobar

फिर मैं इस स्क्रिप्ट को निष्पादित करता हूं:

import bar

print bar.a
bar.a = 1
print bar.a
bar.foobar()

यहाँ मैं उम्मीद करता हूँ:

None
1
1

यहाँ मुझे क्या मिलेगा:

None
1
None

क्या कोई मेरी गलत धारणा को समझा सकता है?

जवाबों:


103

आप उपयोग कर रहे हैं from bar import aaआयात मॉड्यूल के वैश्विक दायरे में एक प्रतीक बन जाता है (या आयात विवरण जो भी गुंजाइश होती है)।

जब आप एक नया मान निर्दिष्ट aकरते हैं, तो आप केवल मूल्य मान बदल रहे हैं a, वास्तविक मूल्य नहीं। आयात करने की कोशिश bar.pyके साथ सीधे import barमें __init__.pyऔर सेटिंग से वहाँ अपने प्रयोग का संचालन bar.a = 1। इस तरह, आप वास्तव में संशोधित करेंगे bar.__dict__['a']जो aइस संदर्भ में 'वास्तविक' मूल्य है ।

यह तीन परतों के साथ थोड़ा सा सजाया गया है, लेकिन मॉड्यूल में इसका bar.a = 1मूल्य बदल aजाता barहै जिसे वास्तव में कहा जाता है __init__.py। यह मूल्य में परिवर्तन नहीं होता की aकि foobarक्योंकि देखता है foobarवास्तविक फ़ाइल में जीवन bar.pybar.bar.aयदि आप इसे बदलना चाहते हैं तो आप सेट कर सकते हैं ।

यह कथन के from foo import barरूप का उपयोग करने के खतरों में से एक importहै: यह barदो प्रतीकों में विभाजित हो जाता है, एक विश्व स्तर पर दिखाई देता है, fooजिसमें से मूल मूल्य की ओर इशारा करना शुरू होता है और एक अलग प्रतीक उस दायरे में दिखाई देता है जहां importकथन निष्पादित होता है। जहां एक प्रतीक बिंदुओं को बदलना उस मूल्य को नहीं बदलता है जो उसने इंगित किया था।

reloadइंटरएक्टिव इंटरप्रेटर से मॉड्यूल की कोशिश करते समय इस तरह का सामान एक हत्यारा है ।


धन्यवाद! आपके जवाब ने शायद मुझे अपराधी की तलाश में कई घंटे बचाए।
jnns

यहां तक ​​कि ऐसा लगता है कि bar.bar.aअधिकांश उपयोग मामलों में भी दृष्टिकोण बहुत मदद नहीं करेगा। संकलन या मॉड्यूल लोडिंग और रनटाइम असाइनमेंट को मिलाना शायद एक कमजोर विचार है क्योंकि आप खुद को भ्रमित (या अपने कोड का उपयोग करने वाले अन्य) करेंगे। खासकर ऐसी भाषाओं में जो इसके बारे में कुछ असंगत व्यवहार करती हैं, जैसे कि यकीनन अजगर करता है।
13

26

इस सवाल के साथ कठिनाई का एक स्रोत है कि आप नाम के एक कार्यक्रम है bar/bar.py: import barआयात या तो bar/__init__.pyया bar/bar.py, जहां यह किया जाता है, जो यह ट्रैक करने के लिए एक छोटे से बोझिल जो बनाता है के आधार पर aहै bar.a

यहाँ दिया गया है कि यह कैसे काम करता है:

क्या होता है यह समझने की कुंजी यह महसूस करना है कि आप में __init__.py,

from bar import a

प्रभाव में कुछ ऐसा करता है

a = bar.a
# … where bar = bar/bar.py (as if bar were imported locally from __init__.py)

और एक नया चर परिभाषित करता है ( bar/__init__.py:aयदि आप चाहें तो)। इस प्रकार, आपका मूल नाम ( ) from bar import aमें __init__.pyबांधता है । यही कारण है कि आप कर सकते हैं में : इस मामले में, यह स्पष्ट है कि आप दोनों है और एक अलग चर नाम (आपके मामले में, दो चर के नाम सिर्फ दोनों होना करने के लिए होता है , लेकिन वे अभी भी अलग नामस्थान में रहते हैं: में , वे हैं और )।bar/__init__.py:abar.py:aNonefrom bar import a as a2__init__.pybar/bar.py:abar/__init__.py:a2a__init__.pybar.aa

अब, जब आप करते हैं

import bar

print bar.a

आप चर bar/__init__.py:a( import barअपने आयात के बाद से bar/__init__.py) तक पहुँच रहे हैं । यह वह चर है जिसे आप संशोधित करते हैं (1 से)। आप चर की सामग्री को नहीं छू रहे हैं bar/bar.py:a। तो जब आप बाद में करते हैं

bar.foobar()

आप कॉल करते हैं bar/bar.py:foobar(), जो चर aको एक्सेस करता है bar/bar.py, जो अभी भी है None(जब foobar()परिभाषित किया गया है, तो यह चर नामों को एक बार और सभी के लिए बांधता है, इसलिए यह aहै bar.pyकि bar.py:a, किसी अन्य aमॉड्यूल में परिभाषित कोई अन्य चर नहीं है - क्योंकि aसभी आयातित मॉड्यूल में कई चर हो सकते हैं )। इसलिए आखिरी Noneआउटपुट।

निष्कर्ष: किसी भी मॉड्यूल के होने से import bar, किसी भी अस्पष्टता से बचने के लिए सबसे अच्छा है (क्योंकि निर्देशिका पहले से ही एक पैकेज बनाती है, जिसे आप आयात भी कर सकते हैं )।bar/bar.pybar.__init__.pybar/import bar


12

दूसरा तरीका लगाने के लिए: इस गलत धारणा को बनाना बहुत आसान है। यह चुपके से पाइथन भाषा के संदर्भ में परिभाषित किया गया है: प्रतीक के बजाय ऑब्जेक्ट का उपयोग । मेरा सुझाव है कि पायथन भाषा संदर्भ इसे और अधिक स्पष्ट और कम विरल बनाये ।।

fromप्रपत्र नहीं बाँध मॉड्यूल का नाम है: यह पहचानकर्ता की सूची के माध्यम से चला जाता है, कदम (1) में पाया मॉड्यूल में उनमें से हर एक लग रहा है, और करने के लिए स्थानीय नाम स्थान में नाम बांधता वस्तु इस प्रकार पाया।

तथापि:

जब आप आयात करते हैं, तो आप आयातित प्रतीक के वर्तमान मूल्य को आयात करते हैं और इसे अपने नाम स्थान में जोड़ते हैं। आप एक संदर्भ आयात नहीं कर रहे हैं, आप प्रभावी रूप से एक मूल्य आयात कर रहे हैं।

इस प्रकार, का अद्यतन मूल्य प्राप्त करने के लिए i, आपको एक चर आयात करना होगा जो उस प्रतीक का एक संदर्भ रखता है।

दूसरे शब्दों में, आयात importJAVA की तरह नहीं है , externalC / C ++ में घोषणा या यहां तक ​​कि usePERL में एक खंड भी ।

बल्कि, पायथन में निम्नलिखित कथन:

from some_other_module import a as x

अधिक है की तरह कश्मीर एंड आर सी में निम्नलिखित कोड:

extern int a; /* import from the EXTERN file */

int x = a;

(चेतावनी: पायथन मामले में, "a" और "x" मूल रूप से वास्तविक मूल्य का संदर्भ हैं: आप INT की प्रतिलिपि नहीं बना रहे हैं, आप संदर्भ पते की प्रतिलिपि बना रहे हैं)


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

2
मुझे काफी असहमत होना पड़ा है। आयात करना / शामिल करना / उपयोग करना संदर्भ प्रपत्र का उपयोग करने का एक लंबा इतिहास है और हर दूसरी भाषा के बारे में जानकारी नहीं है।
मार्क गेरोलिमेटोस

4
दमिति, मैंने रिटर्न मारा ... इस संदर्भ के अनुसार आयात की उम्मीद है (@ प्रति के अनुसार)। वास्तव में, एक नया पायथन प्रोग्रामर, चाहे कितना भी अनुभवी हो, इसे "लुक आउट" तरह से बताना होगा। ऐसा कभी नहीं होना चाहिए: सामान्य उपयोग के आधार पर, पायथन ने गलत रास्ता अपनाया। यदि आवश्यकता हो तो एक "आयात मूल्य" बनाएँ, लेकिन आयात के समय मूल्यों के साथ प्रतीकों को भ्रमित न करें।
मार्क गेरोलिमेटोस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.