web-dev-qa-db-fra.com

À quel point les noms observés sont-ils définis dans les étendues externes?

Je viens de passer à Pycharm et je suis très heureux de tous les avertissements et astuces que cela me fournit pour améliorer mon code. Sauf celui-ci que je ne comprends pas:

This inspection detects shadowing names defined in outer scopes.

Je sais que l’accès à une variable à partir de la portée externe est une mauvaise pratique, mais quel est le problème d’observation de la portée externe?

Voici un exemple où Pycharm me donne le message d'avertissement:

data = [4, 5, 6]

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

print_data(data)
174
Framester

Ce n'est pas grave, mais imaginez une fonction avec quelques arguments supplémentaires et quelques lignes de code. Ensuite, vous décidez de renommer votre argument data en yadda mais vous ratez l’un des endroits où il est utilisé dans le corps de la fonction ... Maintenant data fait référence au global, et vous commencez à avoir des choses étranges. comportement - où vous auriez une beaucoup plus évidente NameError si vous n'aviez pas de nom global data.

Rappelez-vous également que, dans Python, tout est un objet (y compris les modules, les classes et les fonctions); il n'y a donc pas d'espaces de nommage distincts pour les fonctions, les modules ou les classes. Un autre scénario consiste à importer la fonction foo en haut de votre module et à l’utiliser quelque part dans le corps de votre fonction. Ensuite, vous ajoutez un nouvel argument à votre fonction et vous le nommez - malchance - foo.

Enfin, les fonctions et les types intégrés résident également dans le même espace de noms et peuvent être observés de la même manière.

Rien de tout cela n’est un gros problème si vous avez des fonctions courtes, une bonne dénomination et une couverture décente, mais bon, vous devez parfois maintenir un code moins que parfait et être prévenu de ce genre de problèmes pourrait aider.

185

La réponse la plus votée et la plus acceptée à l'heure actuelle et la plupart des réponses omises ici.

Peu importe la longueur de votre fonction ou la façon dont vous appelez votre variable de manière descriptive (pour minimiser, espérons-le, le risque de collision de nom).

Le fait que la variable locale de votre fonction ou son paramètre partage un nom dans l'étendue globale n'a aucune pertinence. Et en fait, quel que soit le soin avec lequel vous choisissez votre nom de variable locale, votre fonction ne peut jamais prévoir "si mon nom génial yadda sera également utilisé à l'avenir comme variable globale?". La solution? Ne vous inquiétez pas pour ça! Le bon état d'esprit est de concevoir votre fonction pour qu'elle consomme l'entrée et uniquement à partir de ses paramètres dans la signature , afin que vous n'ayez pas à vous soucier de ce qui est ( ou sera) dans une portée globale, puis l'observation ne devient plus un problème.

En d'autres termes, le problème d'observation est important uniquement lorsque votre fonction doit utiliser le même nom, variable locale ET variable globale. Mais vous devriez éviter une telle conception en premier lieu. Le code de l'OP N'A PAS vraiment de problème de conception. PyCharm n’est pas assez intelligent et donne un avertissement au cas où. Donc, juste pour rendre PyCharm heureux et pour rendre notre code propre, voyez cette solution en citant la réponse de silyevsk pour supprimer complètement la variable globale.

def print_data(data):
    print data

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

main()

C’est le bon moyen de "résoudre" ce problème, en corrigeant/supprimant votre problème global, sans ajuster votre fonction locale actuelle.

111
RayLuo

Une bonne solution dans certains cas peut être de déplacer le vars + code vers une autre fonction:

def print_data(data):
    print data

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

main()
20
silyevsk

Faire ceci:

data = [4, 5, 6]

def print_data():
    global data
    print(data)

print_data()
7
incompleteET

Cela dépend de la durée de la fonction. Plus la fonction est longue, plus il est probable que quelqu'un la modifiant à l'avenir écrive data en pensant qu'il s'agit du global. En fait, cela signifie local, mais comme la fonction est longue, il n’est pas évident qu’il existe un local portant ce nom.

Pour votre fonction d'exemple, je pense que l'observation du global n'est pas mal du tout.

5
Steve Jessop
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)
4
JoeC

On dirait que c'est 100% code de code pytest

voir:

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

J'ai eu le même problème avec, c'est pourquoi j'ai trouvé ce post;)

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

Et il avertira avec This inspection detects shadowing names defined in outer scopes.

Pour résoudre ce problème, déplacez simplement votre appareil Twitter dans ./tests/conftest.py

# ./tests/conftest.py
import pytest

from syntropy import db


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

Et retirez Twitter appareil comme dans ./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

Cela fera plaisir à QA, à Pycharm et à tout le monde

2
Andrei.Danciuc