आयातित मॉड्यूल में वैश्विक चर की दृश्यता


112

मैं पायथन लिपि में मॉड्यूल आयात करने वाली एक दीवार में चला गया हूं। मैं इस त्रुटि का वर्णन करने के लिए अपनी पूरी कोशिश करूँगा कि मैं इसमें क्यों दौड़ता हूँ, और मैं अपनी समस्या को हल करने के लिए इस विशेष दृष्टिकोण को क्यों बांध रहा हूँ (जिसका वर्णन मैं एक सेकंड में करूँगा):

मान लें कि मेरे पास एक मॉड्यूल है जिसमें मैंने कुछ उपयोगिता फ़ंक्शंस / कक्षाएं परिभाषित की हैं, जो नामस्थान में परिभाषित संस्थाओं का उल्लेख करते हैं जिसमें यह सहायक मॉड्यूल आयात किया जाएगा ("a" ऐसी इकाई हो)

मॉड्यूल 1:

def f():
    print a

और फिर मेरे पास मुख्य कार्यक्रम है, जहां "ए" परिभाषित है, जिसमें मैं उन उपयोगिताओं को आयात करना चाहता हूं:

import module1
a=3
module1.f()

प्रोग्राम को निष्पादित करने से निम्नलिखित त्रुटि हो जाएगी:

Traceback (most recent call last):
  File "Z:\Python\main.py", line 10, in <module>
    module1.f()
  File "Z:\Python\module1.py", line 3, in f
    print a
NameError: global name 'a' is not defined

इसी तरह के सवाल अतीत में पूछे गए हैं (दो दिन पहले, डीएयूएच) और कई समाधान सुझाए गए हैं, हालांकि मैं वास्तव में इन आवश्यकताओं को नहीं समझता हूं। यहाँ मेरा विशेष संदर्भ है:

मैं एक पायथन प्रोग्राम बनाने की कोशिश कर रहा हूं जो एक MySQL डेटाबेस सर्वर से जुड़ता है और GUI के साथ डेटा को प्रदर्शित / संशोधित करता है। स्वच्छता की खातिर, मैंने एक अलग फ़ाइल में सहायक / उपयोगिता MySQL से संबंधित कार्यों का गुच्छा परिभाषित किया है। हालाँकि, वे सभी एक सामान्य चर है, जिसे मैंने मूल रूप से उपयोगिताओं के मॉड्यूल के अंदर परिभाषित किया था , और जो MySQLdb मॉड्यूल से कर्सर ऑब्जेक्ट है। मुझे बाद में एहसास हुआ कि कर्सर ऑब्जेक्ट (जो db सर्वर के साथ संचार करने के लिए उपयोग किया जाता है) को मुख्य मॉड्यूल में परिभाषित किया जाना चाहिए, ताकि मुख्य मॉड्यूल और इसमें आयात होने वाली कोई भी चीज उस वस्तु तक पहुंच सके।

अंतिम परिणाम कुछ इस तरह होगा:

utilities_module.py:

def utility_1(args):
    code which references a variable named "cur"
def utility_n(args):
    etcetera

और मेरा मुख्य मॉड्यूल:

program.py:

import MySQLdb, Tkinter
db=MySQLdb.connect(#blahblah) ; cur=db.cursor()  #cur is defined!
from utilities_module import *

और फिर, जैसे ही मैं किसी भी उपयोगिताओं के कार्यों को कॉल करने का प्रयास करता हूं, यह उपरोक्त "वैश्विक नाम" इस त्रुटि को परिभाषित नहीं करता है।

एक विशेष सुझाव इस तरह के रूप में उपयोगिताओं फ़ाइल में एक "प्रोग्राम आयात कर् से" बयान था:

utilities_module.py:

from program import cur
#rest of function definitions

program.py:

import Tkinter, MySQLdb
db=MySQLdb.connect(#blahblah) ; cur=db.cursor()  #cur is defined!
from utilities_module import *

लेकिन यह चक्रीय आयात या ऐसा कुछ और नीचे की रेखा है, यह भी दुर्घटनाग्रस्त हो जाता है। तो मेरा सवाल है:

नरक में मैं मुख्य मॉड्यूल में परिभाषित "वक्र" ऑब्जेक्ट कैसे बना सकता हूं, उन सहायक कार्यों के लिए दृश्यमान है जो इसे आयात किए जाते हैं?

यदि आपके समाधान के लिए कहीं और पोस्ट किया गया है, तो अपने समय और मेरी गहरी माफी के लिए धन्यवाद। मैं अभी स्वयं उत्तर नहीं पा रहा हूँ और मुझे अपनी पुस्तक में और कोई तरकीब नहीं मिली है।


1
आपके अपडेट के आधार पर: आप शायद वैसे भी एक भी साझा कर्सर नहीं चाहते हैं। एक एकल साझा कनेक्शन , हाँ, लेकिन शापर्स सस्ते होते हैं, और एक ही समय में कई शाप वाले लोगों को जीवित रखने के लिए अक्सर अच्छे कारण होते हैं (उदाहरण के लिए, इसलिए आप उनमें से दो के माध्यम से लॉकस्टेप में कर सकते हैं fetch_allऔर दो सूचियों के माध्यम से पुनरावृति कर सकते हैं , या बस इसलिए कि आपके पास दो अलग-अलग धागे / ग्रीनलेट / कॉलबैक-चेन / जो भी बिना संघर्ष के डेटाबेस का उपयोग कर रहे हैं)।
22

वैसे भी, जो कुछ भी आप साझा करना चाहते हैं, मुझे लगता है कि इस सवाल का जवाब यहाँ स्थानांतरित करने के लिए है db(और curएक अलग मॉड्यूल दोनों कि में अगर आप जोर देते हैं,) programऔर utilities_moduleसे आयात। इस तरह से आपको परिपत्र निर्भरता नहीं मिलती है (मॉड्यूल से प्रोग्राम आयात करता है जो प्रोग्राम आयात करता है) और उनके साथ आने वाला भ्रम।
22

जवाबों:


244

पायथन में ग्लोबल्स एक मॉड्यूल के लिए वैश्विक हैं , सभी मॉड्यूल में नहीं। (कई लोग इससे भ्रमित होते हैं, क्योंकि कहते हैं, सी, एक वैश्विक सभी कार्यान्वयन फाइलों में समान है जब तक कि आप स्पष्ट रूप से इसे नहीं बनाते हैं static।)

इसे हल करने के विभिन्न तरीके हैं, जो आपके वास्तविक उपयोग के मामले पर निर्भर करता है।


इस रास्ते से नीचे जाने से पहले, अपने आप से पूछें कि क्या यह वास्तव में वैश्विक होना चाहिए। हो सकता है कि आप वास्तव में एक क्लास चाहते हों, fउदाहरण के तौर पर, एक फ्री फंक्शन की बजाय? तब आप कुछ ऐसा कर सकते थे:

import module1
thingy1 = module1.Thingy(a=3)
thingy1.f()

यदि आप वास्तव में एक वैश्विक चाहते हैं, लेकिन इसका उपयोग करना है module1, तो इसे उस मॉड्यूल में सेट करें।

import module1
module1.a=3
module1.f()

दूसरी ओर, यदि aबहुत सारे मॉड्यूल द्वारा साझा किया जाता है , तो इसे कहीं और डाल दें, और सभी को इसे आयात करें:

import shared_stuff
import module1
shared_stuff.a = 3
module1.f()

… और मॉड्यूल 1 थिंकपैड में:

import shared_stuff
def f():
    print shared_stuff.a

fromजब तक वेरिएबल स्थिर न हो, तब तक आयात का उपयोग करें । आयात के समय जो कुछ भी संदर्भित है, उसे from shared_stuff import aएक नया aचर बना देगा shared_stuff.a, और यह नया aचर असाइनमेंट से प्रभावित नहीं होगा shared_stuff.a


या, जिस दुर्लभ मामले में आपको वास्तव में इसकी आवश्यकता है वह वास्तव में हर जगह वैश्विक होना चाहिए, बिलिन की तरह, इसे बिलिन मॉड्यूल में जोड़ें। सटीक विवरण अजगर 2.x और 3.x के बीच भिन्न होता है। 3.x में, यह इस तरह काम करता है:

import builtins
import module1
builtins.a = 3
module1.f()

12
अच्छा और व्यापक।
किंडल

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

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

1
अद्यतन: धन्यवाद! शेयर्ड_स्टफ दृष्टिकोण ने ठीक काम किया, इससे मुझे लगता है कि मैं किसी भी अन्य मुद्दों के आसपास काम कर सकता हूं।
नुबार्क

1
@DanielArmengod: यदि आपने वास्तव में इसकी आवश्यकता है, तो मैंने बिलिन उत्तर जोड़ा है। (और यदि आपको अधिक विवरणों की आवश्यकता है, तो SO खोजें; बिल्डरों में सामानों को ठीक से कैसे जोड़ा जाए, इस पर कम से कम दो प्रश्न हैं।) लेकिन, जैसा कि बी रीको कहते हैं, आपको लगभग निश्चित रूप से इसकी आवश्यकता नहीं है, या यह चाहते हैं।
अपराह्न

9

वर्कअराउंड के रूप में, आप इस तरह बाहरी परत में पर्यावरण चर स्थापित करने पर विचार कर सकते हैं।

main.py:

import os
os.environ['MYVAL'] = str(myintvariable)

mymodule.py:

import os

myval = None
if 'MYVAL' in os.environ:
    myval = os.environ['MYVAL']

अतिरिक्त सावधानी के तौर पर, उस मामले को संभालें जब MYVAL को मॉड्यूल के अंदर परिभाषित नहीं किया गया है।


5

एक फ़ंक्शन मॉड्यूल के ग्लोबल्स का उपयोग करता है जिसे यह परिभाषित किया गया है। a = 3उदाहरण के लिए, उदाहरण के लिए, आपको सेटिंग करना चाहिए module1.a = 3। इसलिए, यदि आप curवैश्विक utilities_moduleसेट के रूप में उपलब्ध हैं, तो सेट करें utilities_module.cur

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


'आयात मॉड्यूल 1' लिखने के बजाय, यदि उपयोगकर्ता ने 'मॉड्यूल 1 आयात f' से लिखा था, तो मुख्य main.py के वैश्विक नामस्थान में f आ जाएगा। अब main.py में अगर हम f () का उपयोग करते हैं, तो चूंकि a = 3 और f (फंक्शन डेफिनिशन) दोनों ही मुख्य के Globalnamespace में हैं। क्या यह कोई समाधान है? अगर मैं गलत हूं, तो कृपया आप मुझे इस विषय पर किसी भी लेख के लिए निर्देशित कर सकते हैं कृपया
चर

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

5

यह पोस्ट मेरे द्वारा किए गए पायथन व्यवहार के लिए एक अवलोकन मात्र है। हो सकता है कि आपके द्वारा ऊपर पढ़ी गई सलाह आपके लिए काम न करें यदि आपने वही काम किया है जो मैंने नीचे किया है।

अर्थात्, मेरे पास एक मॉड्यूल है जिसमें वैश्विक / साझा चर शामिल हैं (जैसा कि ऊपर बताया गया है):

#sharedstuff.py

globaltimes_randomnode=[]
globalist_randomnode=[]

तब मेरे पास मुख्य मॉड्यूल था जो साझा किए गए सामान को आयात करता है:

import sharedstuff as shared

और कुछ अन्य मॉड्यूल जो वास्तव में इन सरणियों को आबाद करते हैं। इन्हें मुख्य मॉड्यूल द्वारा बुलाया जाता है। इन अन्य मॉड्यूलों से बाहर निकलते समय, मैं स्पष्ट रूप से देख सकता हूं कि सरणियां आबाद हैं। लेकिन जब उन्हें मुख्य मॉड्यूल में वापस पढ़ा गया, तो वे खाली थे। यह मेरे लिए अजीब था (ठीक है, मैं पायथन के लिए नया हूं)। हालाँकि, जब मैं मुख्य मॉड्यूल में sharestuff.py आयात करने के तरीके को बदलता हूं:

from globals import *

यह काम किया (सरणियों आबाद थे)।

मैं तो बस कह रहा हूं'


2

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

मॉड्यूल 1:

cursor = None

def setCursor(cur):
    global cursor
    cursor = cur

def method(some, args):
    global cursor
    do_stuff(cursor, some, args)

मुख्य कार्यक्रम:

import module1

cursor = get_a_cursor()
module1.setCursor(cursor)
module1.method()

2

चूंकि ग्लोबल्स मॉड्यूल विशिष्ट हैं, आप सभी आयातित मॉड्यूल में निम्न फ़ंक्शन जोड़ सकते हैं, और उसके बाद इसका उपयोग कर सकते हैं:

  • उन लोगों के लिए ग्लोबल्स के रूप में एकवचन चर (शब्दकोश प्रारूप में) जोड़ें
  • अपने मुख्य मॉड्यूल ग्लोबल्स को इसमें स्थानांतरित करें ।

addglobals = lambda x: ग्लोबल्स ()। अद्यतन (x)

फिर आपको वर्तमान ग्लोबल्स पर पास होने की आवश्यकता है:

आयात मॉड्यूल

module.addglobals (वैश्विक ())


1

चूँकि मैंने इसे ऊपर के उत्तरों में नहीं देखा है, मैंने सोचा कि मैं अपने साधारण वर्कअराउंड को जोड़ूंगा, जो global_dictकि कॉलिंग मॉड्यूल के ग्लोबल्स की आवश्यकता वाले फ़ंक्शन में एक तर्क जोड़ने के लिए है, और फिर कॉल करते समय फ़ंक्शन में कमांड पास करें; उदाहरण के लिए:

# external_module
def imported_function(global_dict=None):
    print(global_dict["a"])


# calling_module
a = 12
from external_module import imported_function
imported_function(global_dict=globals())

>>> 12

0

ऐसा करने का ओओपी तरीका आपके मॉड्यूल को अनबाउंड विधियों के एक सेट के बजाय एक वर्ग बनाना होगा। तब आप __init__मॉड्यूल विधियों में उपयोग के लिए कॉलर से वेरिएबल्स सेट करने के लिए एक सेटर विधि का उपयोग कर सकते हैं ।

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