Wat is het probleem met schaduwnamen die zijn gedefinieerd in buitenbereiken?

Ik ben net overgestapt naar PyCharm en ik ben erg blij met alle waarschuwingen en hints die het me geeft om mijn code te verbeteren. Behalve deze die ik niet begrijp:

Deze inspectie detecteert schaduwnamen die zijn gedefinieerd in buitenbereiken.

Ik weet dat het een slechte gewoonte is om toegang te krijgen tot variabelen vanuit het buitenste bereik, maar wat is het probleem met het schaduwen van het buitenste bereik?

Hier is een voorbeeld, waarbij PyCharm me het waarschuwingsbericht geeft:

data = [4, 5, 6]
def print_data(data): # <-- Warning: "Shadows 'data' from outer scope
    print data
print_data(data)

Antwoord 1, autoriteit 100%

Er is geen groot probleem in je bovenstaande fragment, maar stel je een functie voor met een paar extra argumenten en een flink aantal regels code. Dan besluit je om je data-argument te hernoemen naar yadda, maar mis je een van de plaatsen waar het wordt gebruikt in de hoofdtekst van de functie… Nu dataverwijst naar de globale, en je begint raar gedrag te vertonen – waarbij je een veel duidelijkere NameErrorzou hebben als je geen globale naam had data.

Onthoud ook dat in Python alles een object is (inclusief modules, klassen en functies), dus er zijn geen aparte naamruimten voor functies, modules of klassen. Een ander scenario is dat u functie foobovenaan uw module importeert en deze ergens in uw functielichaam gebruikt. Vervolgens voeg je een nieuw argument toe aan je functie en noem je het – pech – foo.

Ten slotte leven ingebouwde functies en typen ook in dezelfde naamruimte en kunnen ze op dezelfde manier worden geschaduwd.

Dit is allemaal niet zo’n probleem als je korte functies, goede naamgeving en een behoorlijke unit-testdekking hebt, maar goed, soms moet je minder dan perfecte code onderhouden en gewaarschuwd worden voor dergelijke mogelijke problemen kan helpen.

p>


Antwoord 2, autoriteit 75%

Het momenteel meest gewaardeerde en geaccepteerde antwoorden de meeste antwoorden hier slaan de plank mis.

Het maakt niet uit hoe lang uw functie is, of hoe u uw variabele een beschrijvende naam geeft (om hopelijk de kans op mogelijke naambotsing te minimaliseren).

Het feit dat de lokale variabele van uw functie of de parameter ervan toevallig een naam deelt in het globale bereik, is volledig irrelevant. En in feite, hoe zorgvuldig je de naam van je lokale variabele ook kiest, je functie kan nooit voorzien “of mijn coole naam yaddain de toekomst ook als globale variabele zal worden gebruikt?”. De oplossing? Maak je daar gewoon geen zorgen over! De juiste manier van denken is om uw functie zo te ontwerpen dat invoer wordt gebruikt van en alleen van de parameters in handtekening. Op die manier hoeft u zich geen zorgen te maken over wat er in de wereldwijde reikwijdte is (of zal zijn), en dan wordt schaduwen helemaal geen probleem.

Met andere woorden, het schaduwprobleem is alleen van belang wanneer uw functie dezelfde naam lokale variabele ende globale variabele moet gebruiken. Maar u moet een dergelijk ontwerp in de eerste plaats vermijden. De code van de OP heeft nietecht zo’n ontwerpprobleem. Het is gewoon dat PyCharm niet slim genoeg is en een waarschuwing geeft voor het geval dat. Dus, om PyCharm blij te maken en onze code schoon te maken, bekijk deze oplossing die citeert uit silyevsk’s antwoordom de globale volledig variabel.

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

Dit is de juiste manier om dit probleem op te lossen, door uw wereldwijde ding te bevestigen / verwijderen, niet de huidige lokale functie aanpassen.


Antwoord 3, Autoriteit 14%

Een goede oplossing in sommige gevallen kan zijn om de variabelen en code naar een andere functie te verplaatsen:

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

Antwoord 4, Autoriteit 2%

Ik hou van een groene vinkje in de rechterbovenhoek in Pycharm. Ik voeg de variabele namen bij met een onderstrepingsteken om deze waarschuwing te wissen, zodat ik me kan concentreren op de belangrijke waarschuwingen.

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

Antwoord 5, Autoriteit 2%

Het hangt ervan af hoe lang de functie is. Hoe langer de functie, hoe groter de kans dat iemand het in de toekomst aanpast zal schrijven dataDenken dat het het globale betekent. In feite betekent het de lokale, maar omdat de functie zo lang is, is het niet duidelijk voor hen dat er een local met die naam bestaat.

Voor uw voorbeeldfunctie denk ik dat schaduwing van het globaal helemaal niet slecht is.


Antwoord 6, Autoriteit 2%

Doe dit:

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

Antwoord 7

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)

Antwoord 8

Het lijkt erop dat het 100% een pytestcodepatroon is.

Zie:

pytest-fixtures: expliciet , modulair, schaalbaar

Ik had er hetzelfde probleem mee, en daarom vond ik dit bericht 😉

# ./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

En het zal waarschuwen met This inspection detects shadowing names defined in outer scopes.

Om dat op te lossen, verplaatst u uw twitter-fixture naar ./tests/conftest.py

# ./tests/conftest.py
import pytest
from syntropy import db
@pytest.fixture
def twitter():
    twitter_ = db.Twitter()
    twitter_._debug = True
    return twitter_

En verwijder de twitter-fixture, zoals in ./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

Dit zal QA, PyCharm en iedereen gelukkig maken.

Other episodes