Właśnie przełączyłem się na Pycharm i jestem bardzo zadowolony ze wszystkich ostrzeżeń i wskazówek, które zapewnia mi poprawę mojego kodu. Z wyjątkiem tego, którego nie rozumiem:

This inspection detects shadowing names defined in outer scopes.

Wiem, że jest zła praktyka dostępu do zmiennej z zakresu zewnętrznego, ale jaki jest problem z cieniowaniem zasięgu zewnętrznego?

Oto jeden przykład, gdzie Pycharm daje mi wiadomość ostrzegawczą:

data = [4, 5, 6]

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

print_data(data)
226
Framester 21 listopad 2013, 19:35

8 odpowiedzi

Najlepsza odpowiedź

Nie ma wielkiej transakcji w powyższym fragmencie, ale wyobraź sobie funkcję z kilkoma kolejnymi argumentami i dość kilkoma liniami kodu. Następnie zdecydujesz się zmienić nazwę argumentu data jako yadda, ale brakuje jednej z miejsc, które jest używane w ciele funkcji ... teraz {x2}} odnosi się do globalnego, a zaczynasz mieć dziwnie zachowanie - gdzie miałbyś znacznie bardziej oczywisty NameError, jeśli nie miałeś globalnej nazwy data.

Pamiętaj również, że w Pythonie wszystko jest obiektem (w tym moduły, klasy i funkcje), więc nie ma wyraźnych przestrzeni nazw dla funkcji, modułów lub klas. Innym scenariuszem jest importowanie funkcji foo na górze modułu i użyj go gdzieś w ciele funkcyjnym. Następnie dodasz nowy argument do swojej funkcji i nazwany go - Bad Luck - foo.

Wreszcie, wbudowane funkcje i typy żyją również w tej samej przestrzeni nazw i mogą być cieniowane w ten sam sposób.

Żaden z tego nie ma problemu, jeśli masz krótkie funkcje, dobre nazywanie i przyzwoite nieludzkie pokrycie, ale czasami trzeba utrzymać mniej niż doskonały kod i ostrzeżenie o tak możliwych kwestiach może pomóc.

243
Peter Mortensen 5 styczeń 2021, 21:58

Dobry obejście w niektórych przypadkach może być przeniesienie kodu Vars + do innej funkcji:

def print_data(data):
    print data

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

main()
28
Peter Mortensen 5 styczeń 2021, 22:11

Zrób to:

data = [4, 5, 6]

def print_data():
    global data
    print(data)

print_data()
6
user8312800user8312800 23 sierpień 2017, 11:13

To zależy od tego czasu funkcja. Im dłużej funkcja, tym więcej szans, że ktoś modyfikujący go w przyszłości będzie napisać data, że oznacza to globalny. W rzeczywistości oznacza to lokalne, ale ponieważ funkcja jest tak daleka, że nie jest dla nich oczywiste, że istnieje lokalny z tą nazwą.

W przypadku swojej przykładowej funkcji myślę, że cieniowanie globalnego nie jest w ogóle złe.

5
Peter Mortensen 5 styczeń 2021, 22:10
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)
3
Peter Mortensen 5 styczeń 2021, 22:09

Wygląda na to, że jest to 100% Wzorzec Kodeksa

Widzieć:

https://docs.pytest.org/en/latest/fixture.html#confetste-py-Sharing-Fixture-Funkcja

Miałem ten sam problem, dlatego znalazłem ten 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

I ostrzega This inspection detects shadowing names defined in outer scopes.

Aby naprawić, aby przesunąć urządzenie twitter do ./tests/conftest.py

# ./tests/conftest.py
import pytest

from syntropy import db


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

I usuń twitter oprawę jak w ./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

To będzie szczęśliwa QA, Pycharm i wszyscy

2
Peter Mortensen 5 styczeń 2021, 22:16

Lubię widzieć zielony kleszcz w prawym górnym rogu w Pycharm. Dołączę nazwy zmiennych za pomocą podkreślenia, aby oczyścić to ostrzeżenie, więc mogę skupić się na ważnych ostrzeżeń.

data = [4, 5, 6]

def print_data(data_): 
    print(data_)

print_data(data)
3
Peter Mortensen 5 styczeń 2021, 22:17

Obecnie najbardziej głosowała i zaakceptowana odpowiedź i większość odpowiedzi tutaj tęskni za punktem.

Nie ma znaczenia, jak długo jest Twoja funkcja, lub jak nazywasz swoją zmienną opiso (miejmy nadzieję zminimalizować szansę na kolizję potencjalnej nazwy).

Fakt, że zmienna lokalna Twoja funkcja lub jego parametr dzieli się nazwy w zakresie globalnego, jest całkowicie nieistotna. W rzeczywistości, bez względu na to, jak dokładnie wybrałeś lokalną nazwę zmiennej, funkcja nigdy nie może przewidzieć "Niezależnie od tego, czy moja fajna nazwa yadda zostanie również wykorzystana jako zmienna globalna w przyszłości?". Rozwiązanie? Po prostu nie martw się o to! Prawidłowy sposób myślenia jest zaprojektowanie funkcji do konsumowania wejścia z i tylko z jego parametrów w podpisie , w ten sposób nie musisz obchodzić, co to jest (lub będzie) w globalnym zakresie, a następnie cieniowanie w ogóle nie staje się problemem.

Innymi słowy, problem cieniowany sprawy tylko wtedy, gdy funkcja musi używać tej samej nazwy zmiennej lokalnej i zmiennej globalnej. Ale powinieneś unikać takiego projektu na pierwszym miejscu. Kod operacyjny nie ma takiego problemu projektowego. Po prostu Pycharm nie jest wystarczająco mądry i daje ostrzeżenie na wszelki wypadek. Tak więc, aby zrobić pycharm szczęśliwy, a także sprawić, że nasz kod czyszczący, zobacz to rozwiązanie cytujące z Odpowiedź Siliwska do usunięcia Zmienna globalna całkowicie.

def print_data(data):
    print data

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

main()

Jest to właściwy sposób na "rozwiązanie" tego problemu, naprawając / usuwając swoją globalną rzecz, nie dostosowując aktualną funkcję lokalną.

167
Peter Mortensen 5 styczeń 2021, 22:13