Dlaczego zmienne globalne są złe? [Zamknięte]

121

Próbuję dowiedzieć się, dlaczego używanie programu globaljest uważane za złą praktykę w Pythonie (i ogólnie w programowaniu). Czy ktoś może wyjaśnić? Mile widziane byłyby również linki zawierające więcej informacji.

LarsVegas
źródło
Głosowanie za ponownym otwarciem - zredagowałem pytanie, aby skupić się na wyjaśnieniach i z dala od zasobów zewnętrznych. (Przypuszczam, że dlatego, że był zamknięty, ale na wszelki wypadek, że to coś z czym pytanie o złej praktyce porównać te inne pytania dotyczące złych praktyk, które są nadal otwarte: eval, import *, konkatenacji ciągów , zmiennejid , cienie atrybutów )
wjandrea

Odpowiedzi:

156

To nie ma nic wspólnego z Pythonem; zmienne globalne są złe w każdym języku programowania.

Jednak stałe globalne nie są koncepcyjnie tym samym, co zmienne globalne ; globalne stałe są całkowicie nieszkodliwe. W Pythonie rozróżnienie między nimi jest wyłącznie konwencją: CONSTANTS_ARE_CAPITALIZEDi globals_are_not.

Powodem, dla którego zmienne globalne są złe, jest to, że umożliwiają one funkcjom wywoływanie ukrytych (nieoczywistych, zaskakujących, trudnych do wykrycia, trudnych do zdiagnozowania) skutków ubocznych, co prowadzi do zwiększenia złożoności, potencjalnie prowadząc do kodu Spaghetti .

Jednak rozsądne użycie stanu globalnego jest dopuszczalne (podobnie jak stan lokalny i zmienność) nawet w programowaniu funkcjonalnym, zarówno w celu optymalizacji algorytmu, zmniejszonej złożoności, buforowania i zapamiętywania, jak i praktyczności portowania struktur pochodzących głównie z imperatywnej bazy kodu.

Podsumowując, na twoje pytanie można odpowiedzieć na wiele sposobów, więc najlepiej jest po prostu wygooglować „dlaczego zmienne globalne są złe”. Kilka przykładów:

Jeśli chcesz wejść głębiej i dowiedzieć się, dlaczego chodzi o efekty uboczne i wiele innych pouczających rzeczy, powinieneś nauczyć się programowania funkcjonalnego:

Erik Kaplun
źródło
35

Tak, w teorii globale (i ogólnie „państwo”) są złe. W praktyce, jeśli zajrzysz do katalogu pakietów swojego Pythona, zauważysz, że większość modułów zaczyna się od zestawu globalnych deklaracji. Oczywiście ludzie nie mają z nimi problemu.

W szczególności w Pythonie, widoczność elementów globalnych jest ograniczona do modułu, dlatego nie ma „prawdziwych” elementów globalnych, które wpływają na cały program - co czyni je o wiele mniej szkodliwymi. Kolejna kwestia: nie ma const, więc jeśli potrzebujesz stałej, musisz użyć globalnej.

W mojej praktyce, jeśli zdarzy mi się zmodyfikować global w funkcji, zawsze deklaruję to z global, nawet jeśli technicznie nie ma takiej potrzeby, jak w:

cache = {}

def foo(args):
    global cache

    cache[args] = ...

To sprawia, że ​​manipulacje globali są łatwiejsze do wyśledzenia.

Georg
źródło
3
pod wieloma względami moduł w Pythonie jest podobny do klasy pojedynczej, a wartości globalne modułu są podobne do właściwości klas.
Corley Brigman
9
@CorleyBrigman Klasy Singleton faktycznie często cierpią z powodu tych samych problemów zazwyczaj przypisywanych globalnych :)
Erik Kaplun
4
widoczność modułów Pythona nie jest ograniczona do modułu. Są dostępne w całym tłumaczu i (tutaj ważna rzecz) zmiany mają wpływ na całego tłumacza. To nie jest jak ciąg, który tworzysz instancje ... jest jak modyfikowanie wszystkich instancji. Małpi zapach łaty.
graffic
2
Większość modułów nie zaczyna się od definiowania zmiennych globalnych, z wyjątkiem stałych. Globale są złe, czyli zmienne / stan globalny, a nie stałe.
BlackJack,
2
Używanie globals jest okropnym pomysłem, jednym z powodów może być niemożność prawidłowego testowania funkcji aktualizujących jakiś dowolny słownik, który istnieje „gdzieś”. W rzeczywistości nie można udowodnić, że baza kodu zawierająca elementy globalne działa.
Tomasz Sosiński
10

Osobista opinia na ten temat jest taka, że ​​używanie zmiennych globalnych w logice funkcji oznacza, że ​​jakiś inny kod może zmienić logikę i oczekiwane wyniki tej funkcji, co bardzo utrudni debugowanie (szczególnie w dużych projektach) i utrudni testowanie także.

Ponadto, jeśli weźmiesz pod uwagę inne osoby czytające Twój kod (społeczność open source, koledzy itp.), Będą mieli trudności ze zrozumieniem, gdzie ustawiana jest zmienna globalna, gdzie została zmieniona i czego można się spodziewać po tej zmiennej globalnej. do funkcji izolowanej, że jej funkcjonalność można określić, odczytując samą definicję funkcji.

(Prawdopodobnie) naruszenie definicji czystej funkcji

Uważam, że czysty i (prawie) wolny od błędów kod powinien mieć funkcje możliwie najczystsze (zobacz czyste funkcje ). Czysta funkcja to taka, która ma następujące warunki:

  1. Funkcja zawsze oblicza tę samą wartość wyniku przy tych samych wartościach argumentów . Wartość wynikowa funkcji nie może zależeć od żadnych ukrytych informacji lub stanu, który może się zmienić w trakcie wykonywania programu lub między różnymi wykonaniami programu, ani też nie może zależeć od jakichkolwiek zewnętrznych danych wejściowych z urządzeń we / wy (zwykle - patrz poniżej).
  2. Ocena wyniku nie powoduje żadnego semantycznie obserwowalnego efektu ubocznego lub wyjścia , takiego jak mutacja obiektów mutowalnych lub wyjście do urządzeń I / O.

Posiadanie zmiennych globalnych narusza co najmniej jedno z powyższych, jeśli nie oba, ponieważ kod zewnętrzny może prawdopodobnie spowodować nieoczekiwane rezultaty.

Inna jasna definicja czystych funkcji: „Czysta funkcja to funkcja, która przyjmuje wszystkie swoje dane wejściowe jako jawne argumenty i produkuje wszystkie swoje wyniki jako jawne wyniki ”. [1] . Posiadanie zmiennych globalnych narusza ideę czystych funkcji, ponieważ dane wejściowe i być może jedno z wyjść (zmienna globalna) nie są jawnie podawane ani zwracane.

(Prawdopodobnie) naruszenie PIERWSZEJ zasady testowania jednostkowego

Dalej, że jeśli wziąć pod uwagę jednostki testowanie i zasady pierwszej ( F testy AST I testy ndependent, R epeatable, S elf-zatwierdzania i T imely) prawdopodobnie będzie naruszać niezależnych testach zasada (co oznacza, że testy nie są uzależnione na siebie).

Posiadanie zmiennej globalnej (nie zawsze), ale w większości przypadków (przynajmniej z tego, co widziałem do tej pory) polega na przygotowaniu i przekazaniu wyników do innych funkcji. To również narusza tę zasadę. Jeśli zmienna globalna została użyta w ten sposób (tj. Zmienna globalna użyta w funkcji X musi być najpierw ustawiona w funkcji Y), oznacza to, że aby przetestować funkcję X należy najpierw uruchomić test / uruchomić funkcję Y.

Globale jako stałe

Z drugiej strony, jak wspominali już inni, użycie zmiennej globalnej jako zmiennej „stałej” może być nieco lepsze, ponieważ język nie obsługuje stałych. Jednak zawsze wolę pracować z klasami i mieć „stałe” jako składową klasy i nie używać w ogóle zmiennej globalnej. Jeśli masz kod, którego dwie różne klasy wymagają do współużytkowania zmiennej globalnej, prawdopodobnie będziesz musiał zrefaktoryzować swoje rozwiązanie i uniezależnić swoje klasy.

Uważam, że nie powinno się używać globali. Ale jeśli zostaną użyte, autorzy powinni rozważyć pewne zasady (być może wspomniane powyżej oraz inne zasady i dobre praktyki inżynierii oprogramowania), aby kod był bardziej przejrzysty i prawie wolny od błędów.

Rafael
źródło
1
Podoba mi się, że „globalne, bo stałe to problem” ... ponieważ jeśli projektujesz OO ... to naprawdę jest. Dlaczego ktokolwiek oprócz klasy IdCreator musi znać ID_LEN?
Erik Aronesty
3

Są niezbędne, a ekran jest dobrym przykładem. Jednak w środowisku wielowątkowym lub w którym uczestniczy wielu programistów, w praktyce często pojawia się pytanie: kto (błędnie) to ustawił lub wyczyścił? W zależności od architektury analiza może być kosztowna i często wymagana. Podczas odczytu zmiennej globalnej może być w porządku, zapis do niej musi być kontrolowany, na przykład przez pojedynczy wątek lub klasę chroniącą wątki. Stąd globalne wojny rodzą obawę przed wysokimi kosztami rozwoju możliwymi przez konsekwencje, dla których same są uważane za złe. Dlatego ogólnie dobrą praktyką jest utrzymywanie niskiej liczby zmiennych globalnych.

Horst Schlawutzke
źródło