Відповіді:
Це не має нічого спільного з Python; глобальні змінні погані в будь-якій мові програмування.
Однак глобальні константи концептуально не збігаються з глобальними змінними ; глобальні константи абсолютно нешкідливі. У Python відмінність між цими двома суто умовними умовами: CONSTANTS_ARE_CAPITALIZED
і globals_are_not
.
Причина глобальних змінних погана в тому, що вони дозволяють функціям мати приховані (не очевидні, дивовижні, важко виявити, важко діагностувати) побічні ефекти, що призводить до збільшення складності, що потенційно призводить до коду спагетті .
Однак розумне використання глобального стану є прийнятним (як і локальний стан та змінність) навіть у функціональному програмуванні, або для оптимізації алгоритмів, зменшення складності, кешування та запам'ятовування, або практичності перенесення структур, що походять з переважно імперативної бази даних.
Загалом, на ваше запитання можна відповісти різними способами, тож найкраще ставити на гугл, "чому глобальні змінні погані". Деякі приклади:
Якщо ви хочете піти глибше і з'ясувати, чому виникають побічні ефекти, та багато інших освічуючих речей, вам слід вивчити функціональне програмування:
Так, теоретично глобалісти (і «держава» взагалі) - це зло. На практиці, якщо ви заглянете в каталог пакунків вашого python, ви побачите, що більшість модулів там починаються з купки глобальних декларацій. Очевидно, що у людей з ними немає проблем.
Зокрема, щодо python, видимість глобалів обмежена модулем, тому немає "справжніх" глобальних глобалів, які впливають на всю програму - це робить їх спосіб менш шкідливим. Ще один момент: таких немає const
, тому коли вам потрібна константа, ви повинні використовувати глобальну.
У своїй практиці, якщо мені трапляється модифікувати глобальну функцію, я завжди декларую це global
, навіть якщо в цьому технічно немає потреби, як у:
cache = {}
def foo(args):
global cache
cache[args] = ...
Це полегшує відстеження маніпуляцій глобалів.
Особиста думка з цього приводу полягає в тому, що використання глобальних змінних, що використовуються в логіці функції, означає, що якийсь інший код може змінити логіку та очікуваний вихід цієї функції, що зробить налагодження дуже важким (особливо у великих проектах) і зробить тестування складніше також.
Крім того, якщо ви вважаєте, що інші люди читають ваш код (спільнота з відкритим кодом, колеги тощо), їм буде важко намагатися зрозуміти, де встановлюється глобальна змінна, де була змінена і що чекати від цієї глобальної змінної на противагу до ізольованої функції, її функціональність можна визначити, прочитавши саме визначення функції.
Я вважаю, що чистий і (майже) код помилок повинен мати максимально чисті функції (див. Чисті функції ). Чистою функцією є та, яка має такі умови:
Наявність глобальних змінних є порушенням принаймні одного з вищезазначених, якщо не обидва, так як зовнішній код, ймовірно, може призвести до несподіваних результатів.
Ще одне чітке визначення чистих функцій: "Чиста функція - це функція, яка приймає всі свої вхідні дані як явні аргументи і виробляє всі її результати як явні результати ". [1] . Наявність глобальних змінних порушує уявлення про чисті функції, оскільки вхід і, можливо, один із виходів (глобальна змінна) явно не надається і не повертається.
Далі, якщо ви врахуєте тестування одиниць і ПЕРШИЙ принцип ( F ast тести, I незалежні тести, R epeatable, S elf-Validating та T imely), ймовірно, будуть порушувати принцип Незалежних тестів (це означає, що тести не залежать від один на одного).
Мати глобальну змінну (не завжди), але в більшості випадків (принаймні, що я бачив до цього часу) - це готувати та передавати результати іншим функціям. Це також порушує цей принцип. Якщо глобальна змінна була використана таким чином (тобто глобальна змінна, яка використовується у функції X спочатку повинна бути встановлена у функції Y), це означає, що для одиниці тестової функції X потрібно спочатку запустити функцію тесту / запуску Y.
З іншого боку, як вже згадували інші люди, якщо глобальна змінна використовується як "константа" змінної, може бути трохи краще, оскільки мова не підтримує константи. Однак я завжди вважаю за краще працювати з класами і мати "константи" як члена класу, а не використовувати глобальну змінну взагалі. Якщо у вас є код, який потрібен двом різним класам для спільної глобальної змінної, вам, ймовірно, потрібно переробити рішення і зробити класи незалежними.
Я не вірю, що глобали не слід використовувати. Але якщо вони будуть використані, автори повинні врахувати деякі принципи (можливо, згадані вище, а також інші принципи інженерії програмного забезпечення та належну практику) для отримання більш чистого та майже помилкового коду.
Вони важливі, екран є хорошим прикладом. Однак у багатопотоковому середовищі або із залученням багатьох розробників на практиці часто виникає питання: хто (помилково) встановив чи очистив це? Залежно від архітектури, аналіз може бути дорогим і вимагати часто. Під час читання глобального var може бути нормальним, запис у нього повинен контролюватися, наприклад, одним потоком або безпечним класом потоку. Отже, у глобальній варі виникає страх перед високими витратами на розвиток, можливими наслідками, які самі вважаються злими. Тому в цілому, це хороша практика, щоб кількість глобальних варіантів залишалася низькою.
eval
,import *
, конкатенація , змінномуid
, тінь атрибутів )