बाहरी स्कोप में परिभाषित छायांकन कितना बुरा है?


208

मैंने अभी-अभी पिचरम पर स्विच किया है और मैं सभी चेतावनियों और संकेतों के बारे में बहुत खुश हूं जो मुझे अपने कोड को बेहतर बनाने के लिए प्रदान करता है। इसको छोड़कर जो मुझे समझ में नहीं आता है:

This inspection detects shadowing names defined in outer scopes.

मुझे पता है कि बाहरी दायरे से चर का उपयोग करना बुरा है, लेकिन बाहरी दायरे को छाया देने में क्या समस्या है?

यहाँ एक उदाहरण है, जहाँ Pycharm ने मुझे चेतावनी संदेश दिया है:

data = [4, 5, 6]

def print_data(data): # <-- Warning: "Shadows 'data' from outer scope
    print data

print_data(data)

1
इसके अलावा मैंने स्ट्रिंग के लिए खोज की "यह निरीक्षण पता लगाता है ..." लेकिन pycharm में कुछ भी नहीं मिला ऑनलाइन मदद: jetbrains.com/pycharm/webhelp/getting-help.html
Framester

1
PyCharm में इस संदेश को बंद करने के लिए: <Ctrl> + <Alt> + s (सेटिंग्स), संपादक , निरीक्षण , " बाहरी स्कोपों ​​से छायांकन नाम "। अनचेक करें।
चैमग

जवाबों:


222

आपके उपरोक्त स्निपेट में कोई बड़ी बात नहीं है, लेकिन कुछ और तर्कों के साथ एक फ़ंक्शन की कल्पना करें और कोड की कुछ और लाइनें। फिर आप अपने dataतर्क का नाम बदलने का फैसला करते हैं, yaddaलेकिन फ़ंक्शन के शरीर में उपयोग की जाने वाली जगहों में से एक को याद करते हैं ... अब dataवैश्विक को संदर्भित करता है, और आप अजीब व्यवहार करना शुरू कर देते हैं - जहां आपके पास बहुत अधिक स्पष्ट होगा NameErrorयदि आपने नहीं किया एक वैश्विक नाम है data

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

अंत में, अंतर्निहित कार्य और प्रकार भी एक ही नाम स्थान पर रहते हैं और उसी तरह से छायांकित किया जा सकता है।

इसमें से कोई भी एक समस्या नहीं है यदि आपके पास कम कार्य हैं, अच्छा नामकरण और एक सभ्य अनैतिक कवरेज है, लेकिन ठीक है, कभी-कभी आपको सही कोड से कम बनाए रखना पड़ता है और ऐसे संभावित मुद्दों के बारे में चेतावनी दी जा सकती है।


21
सौभाग्य से PyCharm (जैसा कि ओपी द्वारा उपयोग किया जाता है) का एक बहुत अच्छा नाम बदलना ऑपरेशन है जो चर का नाम बदलकर हर जगह उसी दायरे में उपयोग किया जाता है, जिससे नाम बदलने की त्रुटियों की संभावना कम हो जाती है।
wojtow

PyCharm के नाम बदलने के ऑपरेशन के अलावा, मैं बाहरी दायरे को संदर्भित करने वाले चर के लिए विशेष वाक्यविन्यास हाइलाइट करना पसंद करूंगा। इन दोनों को इस बार छाया संकल्प खेल अप्रासंगिक खपत करना चाहिए।
सिंह

साइड नोट: आप nonlocalबाहरी स्कोर को संदर्भित करने के लिए कीवर्ड का उपयोग कर सकते हैं (जैसे क्लोजर में) स्पष्ट। ध्यान दें कि यह छायांकन से अलग है, क्योंकि यह स्पष्ट रूप से बाहर से चर को छाया नहीं देता है।
फेलिक्स डी।

148

वर्तमान में सबसे अधिक मतदान और स्वीकार किए जाते हैं उत्तर और यहाँ अधिकांश उत्तर बिंदु याद आते हैं।

इससे कोई फर्क नहीं पड़ता कि आपका कार्य कितना लंबा है, या आप अपने चर का नाम कैसे वर्णन करते हैं (संभावित नाम टक्कर की संभावना को कम करने के लिए)।

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

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

def print_data(data):
    print data

def main():
    data = [4, 5, 6]
    print_data(data)

main()

इस समस्या को "हल" करने का उचित तरीका है, अपनी वैश्विक चीज़ को ठीक करना / हटाना, न कि अपने वर्तमान स्थानीय फ़ंक्शन को समायोजित करना।


11
अच्छी तरह से, यकीन है, एक आदर्श दुनिया में, आप एक टाइपो बनाते हैं, या जब आप पैरामीटर बदलते हैं, तो अपनी किसी एक खोज-प्रतिस्थापन को भूल जाते हैं, लेकिन गलतियाँ होती हैं और यही बात PyCharm कह रही है - "चेतावनी - तकनीकी रूप से कुछ भी त्रुटि नहीं है, लेकिन यह आसानी से एक समस्या बन सकता है "
dwanderson

1
@dwanderson जिस स्थिति का आपने उल्लेख किया है वह कोई नई बात नहीं है, यह वर्तमान में चुने गए उत्तर में स्पष्ट रूप से वर्णित है। हालाँकि, मैं जिस बिंदु को बनाने की कोशिश कर रहा हूं, वह यह है कि हमें वैश्विक वैरिएबल से बचना चाहिए, न कि वैरिएबल वैरिएबल से बचना चाहिए। बाद वाली बात याद आती है। उसे ले लो? समझ गया?
रायलूओ

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

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

2
इस बात से सहमत। यहां समस्या पाइथन स्कूपिंग की है। वर्तमान दायरे से बाहर की वस्तुओं के लिए गैर-स्पष्ट पहुंच परेशानी के लिए पूछ रही है। कौन चाहेगा कि! शर्म की बात है क्योंकि अन्यथा पायथन एक अच्छी तरह से सोची गई भाषा है (मॉड्यूल के नामकरण में एक समान अस्पष्टता को समझते हुए नहीं)।
कोडकैबी

24

कुछ मामलों में अच्छा वर्कअराउंड वर्जन + कोड को दूसरे फंक्शन में ले जाने के लिए हो सकता है:

def print_data(data):
    print data

def main():
    data = [4, 5, 6]
    print_data(data)

main()

हाँ। मुझे लगता है कि एक अच्छा विचारधारा स्थानीय वैरिएबल और वैश्विक चरों को फिर से सक्रिय करने में सक्षम है। आपकी टिप वास्तव में आदिम
विचारधारा के

5

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

आपके उदाहरण समारोह के लिए, मुझे लगता है कि वैश्विक छायांकन बिल्कुल भी बुरा नहीं है।


5

यह करो:

data = [4, 5, 6]

def print_data():
    global data
    print(data)

print_data()

3
data = [4, 5, 6] #your global variable

def print_data(data): # <-- Pass in a parameter called "data"
    print data  # <-- Note: You can access global variable inside your function, BUT for now, which is which? the parameter or the global variable? Confused, huh?

print_data(data)

47
मैं एक के लिए भ्रमित नहीं हूं। यह स्पष्ट रूप से पैरामीटर है।

2
@delnan आप इस तुच्छ उदाहरण में भ्रमित नहीं हो सकते हैं, लेकिन क्या होगा अगर अन्य कार्यों को परिभाषित किया जाए जो वैश्विक उपयोग किए गए हैं data, सभी कोड की कुछ सौ लाइनों के भीतर गहरे हैं?
बजे जॉन कोलंडुनी

13
@ हेवीलाइट मुझे पास के अन्य कार्यों को देखने की आवश्यकता नहीं है। मैं इस फ़ंक्शन को केवल देखता हूं और देख सकता हूं कि इस फ़ंक्शन dataमें एक स्थानीय नाम है , इसलिए मैं यह जांचने / याद करने से भी परेशान नहीं हूं कि क्या एक ही नाम का एक वैश्विक अस्तित्व है , अकेले ही इसमें शामिल हैं।

4
मुझे नहीं लगता कि यह तर्क मान्य है, केवल इसलिए कि एक वैश्विक का उपयोग करने के लिए, आपको फ़ंक्शन के अंदर "वैश्विक डेटा" को परिभाषित करने की आवश्यकता होगी। अन्यथा, वैश्विक सुलभ नहीं है।
कोडीएफ

1
@CodyF False- अगर आप को परिभाषित नहीं है, लेकिन सिर्फ उपयोग करने का प्रयास करें data, यह स्कोप के माध्यम से जब तक यह एक पाता है, लग रहा है तो यह करता है वैश्विक लगता है datadata = [1, 2, 3]; def foo(): print(data); foo()
dwanderson

3

मुझे pycharm में शीर्ष दाएं कोने में एक हरे रंग की टिक देखना पसंद है। मैं इस चेतावनी को खाली करने के लिए केवल एक अंडरस्कोर के साथ चर नामों को जोड़ता हूं ताकि मैं महत्वपूर्ण चेतावनियों पर ध्यान केंद्रित कर सकूं।

data = [4, 5, 6]

def print_data(data_): 
    print(data_)

print_data(data)

2

यह 100% पाइस्टेस्ट कोड पैटर्न जैसा दिखता है

देख:

https://docs.pytest.org/en/latest/fixture.html#conftest-py-sharing-fixture-functions

मेरे साथ भी यही समस्या थी, यही कारण है कि मुझे यह पद मिला;)

# ./tests/test_twitter1.py
import os
import pytest

from mylib import db
# ...

@pytest.fixture
def twitter():
    twitter_ = db.Twitter()
    twitter_._debug = True
    return twitter_

@pytest.mark.parametrize("query,expected", [
    ("BANCO PROVINCIAL", 8),
    ("name", 6),
    ("castlabs", 42),
])
def test_search(twitter: db.Twitter, query: str, expected: int):

    for query in queries:
        res = twitter.search(query)
        print(res)
        assert res

और इसके साथ चेतावनी देगा This inspection detects shadowing names defined in outer scopes.

इसे ठीक करने के लिए बस अपने twitterफिक्सेटर को मूव करें./tests/conftest.py

# ./tests/conftest.py
import pytest

from syntropy import db


@pytest.fixture
def twitter():
    twitter_ = db.Twitter()
    twitter_._debug = True
    return twitter_

और twitterजैसे में स्थिरता निकालें./tests/test_twitter2.py

# ./tests/test_twitter2.py
import os
import pytest

from mylib import db
# ...

@pytest.mark.parametrize("query,expected", [
    ("BANCO PROVINCIAL", 8),
    ("name", 6),
    ("castlabs", 42),
])
def test_search(twitter: db.Twitter, query: str, expected: int):

    for query in queries:
        res = twitter.search(query)
        print(res)
        assert res

यह QA, Pycharm और सभी को खुश करेगा

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