क्रॉस-मॉड्यूल चर कैसे बनाएं?


122

__debug__यह हर मॉड्यूल को प्रभावित करता है क्योंकि चर भाग में उपयोगी है। यदि मैं एक और चर बनाना चाहता हूं जो उसी तरह से काम करता है, तो मैं यह कैसे करूंगा?

चर (चलो मूल हो और इसे 'फू' कहें) वास्तव में वैश्विक होना जरूरी नहीं है, इस अर्थ में कि अगर मैं एक मॉड्यूल में फू को बदलता हूं, तो यह दूसरों में अपडेट किया जाता है। अगर मैं अन्य मॉड्यूल आयात करने से पहले फू सेट कर सकता हूं, तो मैं ठीक हो जाऊंगा और फिर वे इसके लिए समान मूल्य देखेंगे।

जवाबों:


114

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

थिंकपैड शामिल हैं

print foo

b.py

import __builtin__
__builtin__.foo = 1
import a

परिणाम यह है कि "1" छपा है।

संपादित करें:__builtin__ मॉड्यूल स्थानीय प्रतीक के रूप में उपलब्ध है __builtins__- इन उत्तरों दोनों के बीच विसंगति के लिए कारण नहीं है कि। यह भी ध्यान दें कि अजगर __builtin__में नाम बदल दिया गया builtinsहै।


2
कोई भी कारण, कि आप इस स्थिति को पसंद नहीं करते हैं?
सॉफ्टवेयर उत्साही

31
एक बात के लिए, यह लोगों की उम्मीदों को तोड़ता है जब वे कोड पढ़ रहे होते हैं। "यह 'फू' प्रतीक किसके यहाँ इस्तेमाल किया जा रहा है? मैं यह क्यों नहीं देख सकता कि इसे कहाँ परिभाषित किया गया है?"
कर्ट हेगनलोचर

9
यदि आप एक वास्तविक बिल्टिन के रूप में चुने गए नाम का उपयोग करना शुरू कर देते हैं, तो यह कहर बरपाने ​​के लिए अतिसंवेदनशील होता है।
intuited

4
आयातित मॉड्यूल के साथ db कनेक्शन साझा करने जैसी चीजों के लिए यह एक अच्छा समाधान है। एक पवित्रता की जाँच के रूप में, मैं यह सुनिश्चित करता हूं कि आयातित मॉड्यूल का दावा किया जाए hasattr(__builtin__, "foo")
माइक एलिस

4
किसी को भी इस जवाब को पढ़ने के लिए: मत! करना ! यह ! वास्तव में, नहीं।
ब्रूनो डेथिलियर्स 11

161

यदि आपको एक वैश्विक क्रॉस-मॉड्यूल चर की आवश्यकता है, तो शायद सरल वैश्विक मॉड्यूल-स्तरीय चर पर्याप्त होगा।

a.py:

var = 1

b.py:

import a
print a.var
import c
print a.var

c.py:

import a
a.var = 2

परीक्षा:

$ python b.py
# -> 1 2

वास्तविक दुनिया का उदाहरण: Django के global_settings.py (हालांकि Django ऐप्स सेटिंग्स का उपयोग ऑब्जेक्ट आयात करके किया जाता है django.conf.settings)।


3
बेहतर है क्योंकि यह संभावित नामस्थान संघर्ष से बचा जाता है
bgw

क्या होगा यदि आप जो मॉड्यूल आयात कर रहे हैं, इस मामले में a.py, उसमें शामिल है main()? फर्क पड़ता है क्या?
sedeh

4
@ बरदे: नहीं। यदि एक स्क्रिप्ट के रूप में भी एरोफ़िक्स चलाया जाता है, तो if __name__=="__main__"आयात पर अप्रत्याशित कोड चलाने से बचने के लिए इसमें गार्ड का उपयोग करें ।
JFS

6
वास्तविक दुनिया में, आपको इस समाधान के साथ थोड़ा सावधान रहना होगा। यदि कोई प्रोग्रामर आपके 'ग्लोबल' वेरिएबल को 'एक आयात संस्करण से' का उपयोग करता है, तो (c.py में इस भिन्नता को आज़माएं) वे आयात के समय चर की एक प्रति प्राप्त करते हैं।
पॉल व्हिप

1
@PaulWhipp: गलत (संकेत: उपयोग id()पहचान की जाँच करने के लिए)
JFS

25

मेरा मानना ​​है कि ऐसी बहुत सी परिस्थितियाँ हैं, जिनमें इसका कोई मतलब नहीं है और यह प्रोग्रामिंग को सरल बनाता है कुछ ग्लोबल्स जो कई (कसकर युग्मित) मॉड्यूल के पार जाने जाते हैं। इस भावना में, मैं ग्लोबल्स के एक मॉड्यूल के विचार पर थोड़ा विस्तार करना चाहूंगा जो कि उन मॉड्यूल द्वारा आयात किया जाता है जिन्हें उन्हें संदर्भित करने की आवश्यकता होती है।

जब केवल एक ऐसा मॉड्यूल होता है, तो मैं इसे "जी" नाम देता हूं। इसमें, मैं हर वैरिएबल के लिए डिफ़ॉल्ट मान प्रदान करता हूं जिसे मैं वैश्विक मानता हूं। प्रत्येक मॉड्यूल में जो उनमें से किसी का भी उपयोग करता है, मैं "जी आयात संस्करण से" का उपयोग नहीं करता हूं, क्योंकि इससे केवल एक स्थानीय चर निकलता है जो आयात के समय केवल जी से आरंभ किया जाता है। मैं प्रपत्र g.var में सबसे अधिक संदर्भ देता हूं, और "जी।" एक निरंतर अनुस्मारक के रूप में कार्य करता है कि मैं एक चर के साथ काम कर रहा हूं जो अन्य मॉड्यूल के लिए संभावित रूप से सुलभ है।

यदि ऐसे वैश्विक चर का मान किसी फ़ंक्शन में किसी मॉड्यूल में अक्सर उपयोग किया जाना है, तो वह फ़ंक्शन एक स्थानीय प्रतिलिपि बना सकता है: var = g.var। हालाँकि, यह महसूस करना महत्वपूर्ण है कि var के असाइनमेंट लोकल हैं, और ग्लोबल g.var को असाइनमेंट में स्पष्ट रूप से g.var को संदर्भित किए बिना अपडेट नहीं किया जा सकता है।

ध्यान दें कि आपके पास कई ऐसे ग्लोबल्स मॉड्यूल हो सकते हैं जो आपके मॉड्यूल के विभिन्न सबसेट द्वारा साझा किए जाते हैं ताकि चीजों को थोड़ा और कसकर नियंत्रित किया जा सके। मेरे ग्लोबल्स मॉड्यूल के लिए संक्षिप्त नाम का उपयोग करने का कारण यह है कि उनमें से घटनाओं के साथ कोड को बहुत अधिक अव्यवस्थित करने से बचें। केवल थोड़े से अनुभव के साथ, वे केवल 1 या 2 वर्णों के साथ पर्याप्त रूप से महामारी बन जाते हैं।

यह तब भी संभव है कि जब कोई x पहले से ही g में परिभाषित नहीं किया गया था, तब gx को असाइन करें, और एक अलग मॉड्यूल तब gx तक पहुँच सकता है, हालाँकि दुभाषिया इसकी अनुमति देता है, फिर भी यह दृष्टिकोण इतना पारदर्शी नहीं है, और मैं इससे बचता हूँ यह। असाइनमेंट के लिए चर नाम में टाइपो के परिणामस्वरूप गलती से जी में एक नया चर बनाने की संभावना अभी भी है। कभी-कभी डायर (जी) की एक परीक्षा किसी भी आश्चर्यचकित करने वाले नामों की खोज करने के लिए उपयोगी होती है जो इस तरह की दुर्घटना से उत्पन्न हुई हो सकती है।


7
इस दिलचस्प अवलोकन ने मेरी समस्या को हल कर दिया: 'मैं "जी आयात वर्जन से उपयोग नहीं करता हूं", क्योंकि यह केवल एक स्थानीय चर में परिणामित होता है जिसे आयात के समय केवल जी से आरंभ किया जाता है।' यह मानना ​​उचित लगता है कि "from..import" "आयात" के समान है लेकिन यह सच नहीं है।
कर्टिस येलोप

24

एक मॉड्यूल को परिभाषित करें (इसे "ग्लोबलबाज़" कहें) और इसके अंदर परिभाषित चर हैं। इस "pseudoglobal" का उपयोग करने वाले सभी मॉड्यूल को "Globalbaz" मॉड्यूल को आयात करना चाहिए, और इसे "globalbaz.var_name" का उपयोग करके संदर्भित करना चाहिए

यह परिवर्तन की जगह की परवाह किए बिना काम करता है, आप आयात से पहले या बाद में चर को बदल सकते हैं। आयातित मॉड्यूल नवीनतम मूल्य का उपयोग करेगा। (मैंने इसे एक खिलौना उदाहरण में परीक्षण किया)

स्पष्टीकरण के लिए, Globalbaz.py इस तरह दिखता है:

var_name = "my_useful_string"

9

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

मॉड्यूल ए में:

import module_b
my_var=2
module_b.do_something_with_my_globals(globals())
print my_var

मॉड्यूल बी में:

def do_something_with_my_globals(glob): # glob is simply a dict.
    glob["my_var"]=3

7

वैश्विक चर आमतौर पर एक बुरा विचार होते हैं, लेकिन आप इसे असाइन करके यह कर सकते हैं __builtins__:

__builtins__.foo = 'something'
print foo

इसके अलावा, मॉड्यूल स्वयं चर होते हैं जिन्हें आप किसी भी मॉड्यूल से एक्सेस कर सकते हैं। इसलिए यदि आप एक मॉड्यूल को परिभाषित करते हैं, जिसे my_globals.py:

# my_globals.py
foo = 'something'

तब आप इसका उपयोग कहीं से भी कर सकते हैं:

import my_globals
print my_globals.foo

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


3
__builtins__एक CPython की ख़ासियत है, आपको वास्तव में इसका उपयोग नहीं करना चाहिए - बेहतर उपयोग __builtin__(या builtinsपायथन 3 में) स्वीकार किए गए उत्तर शो के रूप में
Tobias Kienzler

5

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

यह आमतौर पर चीजों को करने का एक शानदार तरीका नहीं है - ग्लोबल्स का उपयोग करना शायद ही कभी होता है - लेकिन मुझे लगता है कि यह करने का सबसे साफ तरीका है।


3

मैं एक जवाब पोस्ट करना चाहता था कि एक ऐसा मामला है जहां चर नहीं मिलेगा।

चक्रीय आयात मॉड्यूल व्यवहार को तोड़ सकते हैं।

उदाहरण के लिए:

first.py

import second
var = 1

second.py

import first
print(first.var)  # will throw an error because the order of execution happens before var gets declared.

main.py

import first

इस उदाहरण पर यह स्पष्ट होना चाहिए, लेकिन एक बड़े कोड-बेस में, यह वास्तव में भ्रमित हो सकता है।


1

यह __builtin__नाम स्थान को संशोधित करने जैसा लगता है। इसे करने के लिए:

import __builtin__
__builtin__.foo = 'some-value'

__builtins__सीधे उपयोग न करें (अतिरिक्त "s" पर ध्यान दें) - जाहिर है यह एक शब्दकोश या एक मॉड्यूल हो सकता है। इसे इंगित करने के लिए poin के लिए धन्यवाद, यहां और अधिक पाया जा सकता है

अब fooहर जगह उपयोग के लिए उपलब्ध है।

मैं आमतौर पर ऐसा करने की सलाह नहीं देता, लेकिन इसका उपयोग प्रोग्रामर के ऊपर है।

इसे असाइन करना ऊपर की तरह किया जाना चाहिए, बस सेटिंग foo = 'some-other-value'केवल वर्तमान नामस्थान में सेट होगी।


1
मुझे याद है (COMP.lang.python से) कि सीधे बिल्डरों का उपयोग करने से बचना चाहिए; बजाय, आयात निर्मित और उपयोग कि, के रूप में कर्ट Hagenlocher का सुझाव दिया।
tzot

1

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

def builtin_find(f, x, d=None):
    for i in x:
        if f(i):
            return i
    return d

import __builtin__
__builtin__.find = builtin_find

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

find(lambda i: i < 0, [1, 3, 0, -5, -10])  # Yields -5, the first negative.

नोट: आप यह कर सकते हैं, निश्चित रूप से, शून्य लंबाई के लिए परीक्षण करने के लिए फ़िल्टर और दूसरी पंक्ति के साथ, या एक प्रकार की अजीब रेखा में कमी के साथ, लेकिन मुझे हमेशा लगा कि यह अजीब था।


1

मैं एक डिक्शनरी का उपयोग करके क्रॉस-मॉड्यूल मोडिफायेबल (या म्यूटेबल ) वेरिएबल प्राप्त कर सकता हूं :

# in myapp.__init__
Timeouts = {} # cross-modules global mutable variables for testing purpose
Timeouts['WAIT_APP_UP_IN_SECONDS'] = 60

# in myapp.mod1
from myapp import Timeouts

def wait_app_up(project_name, port):
    # wait for app until Timeouts['WAIT_APP_UP_IN_SECONDS']
    # ...

# in myapp.test.test_mod1
from myapp import Timeouts

def test_wait_app_up_fail(self):
    timeout_bak = Timeouts['WAIT_APP_UP_IN_SECONDS']
    Timeouts['WAIT_APP_UP_IN_SECONDS'] = 3
    with self.assertRaises(hlp.TimeoutException) as cm:
        wait_app_up(PROJECT_NAME, PROJECT_PORT)
    self.assertEqual("Timeout while waiting for App to start", str(cm.exception))
    Timeouts['WAIT_JENKINS_UP_TIMEOUT_IN_SECONDS'] = timeout_bak

लॉन्च test_wait_app_up_failकरते समय, वास्तविक टाइमआउट अवधि 3 सेकंड है।


1

मुझे आश्चर्य हुआ कि क्या वैश्विक चर का उपयोग करने के कुछ नुकसानों से बचना संभव होगा (देखें उदाहरण http://wiki.c2.com/?GlobalVariablesAreBad ) चर के मूल्यों को पारित करने के लिए एक वैश्विक / मॉड्यूल नामस्थान के बजाय एक वर्ग नामस्थान का उपयोग करके। । निम्न कोड इंगित करता है कि दो तरीके अनिवार्य रूप से समान हैं। नीचे बताए अनुसार क्लास नेमस्पेस का उपयोग करने में थोड़ा फायदा है।

निम्नलिखित कोड के टुकड़े यह भी बताते हैं कि विशेषताएँ या चर गतिशील रूप से वैश्विक / मॉड्यूल नामस्थान और वर्ग नामस्थान दोनों में बनाए और हटाए जा सकते हैं।

wall.py

# Note no definition of global variables

class router:
    """ Empty class """

मैं इस मॉड्यूल को 'दीवार' कहता हूं क्योंकि इसका उपयोग चर को बंद करने के लिए किया जाता है। यह रिक्त स्थान 'राउटर' की वैश्विक चर और वर्ग-व्यापी विशेषताओं को अस्थायी रूप से परिभाषित करने के लिए एक स्थान के रूप में कार्य करेगा।

source.py

import wall
def sourcefn():
    msg = 'Hello world!'
    wall.msg = msg
    wall.router.msg = msg

यह मॉड्यूल दीवार को आयात करता है और एक एकल फ़ंक्शन sourcefnको परिभाषित करता है जो एक संदेश को परिभाषित करता है और इसे दो अलग-अलग तंत्रों द्वारा, एक ग्लोबल्स के माध्यम से और एक राउटर फ़ंक्शन के माध्यम से उत्सर्जित करता है। ध्यान दें कि चर wall.msgऔर wall.router.messageउनके नामस्थानों में पहली बार परिभाषित किए गए हैं।

dest.py

import wall
def destfn():

    if hasattr(wall, 'msg'):
        print 'global: ' + wall.msg
        del wall.msg
    else:
        print 'global: ' + 'no message'

    if hasattr(wall.router, 'msg'):
        print 'router: ' + wall.router.msg
        del wall.router.msg
    else:
        print 'router: ' + 'no message'

यह मॉड्यूल एक फ़ंक्शन को परिभाषित करता है destfnजो स्रोत द्वारा उत्सर्जित संदेशों को प्राप्त करने के लिए दो अलग-अलग तंत्रों का उपयोग करता है। यह इस संभावना के लिए अनुमति देता है कि चर 'msg' मौजूद नहीं हो सकता है। destfnएक बार प्रदर्शित होने के बाद वे चर भी हटा देते हैं।

main.py

import source, dest

source.sourcefn()

dest.destfn() # variables deleted after this call
dest.destfn()

यह मॉड्यूल अनुक्रम में पहले से परिभाषित कार्यों को कॉल करता है। dest.destfnचर के लिए पहली कॉल के बाद wall.msgऔर wall.router.msgअब मौजूद नहीं है।

कार्यक्रम से उत्पादन है:

वैश्विक: नमस्ते दुनिया!
राउटर: नमस्ते दुनिया!
वैश्विक: कोई संदेश
राउटर: कोई संदेश नहीं

उपरोक्त कोड अंशों से पता चलता है कि मॉड्यूल / वैश्विक और वर्ग / वर्ग चर तंत्र अनिवार्य रूप से समान हैं।

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

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