Чому глобальні змінні злі? [зачинено]


121

Я намагаюся з’ясувати, чому використання globalPython (і в цілому програмуванні) вважається поганою практикою. Може хтось пояснить? Також будуть вдячні посилання з додатковою інформацією.


Голосування за повторне відкриття - я відредагував питання, щоб перенести фокус на пояснення та подалі від ресурсів поза межами сайту. (Я припускаю , що це , чому вона була закрита, але тільки в тому випадку , якщо це що - то робити з буттям питання про поганий практиці порівняти ці інші питання про поганий практиці , які все ще відкриті: eval, import *, конкатенація , змінномуid , тінь атрибутів )
wjandrea

Відповіді:


156

Це не має нічого спільного з Python; глобальні змінні погані в будь-якій мові програмування.

Однак глобальні константи концептуально не збігаються з глобальними змінними ; глобальні константи абсолютно нешкідливі. У Python відмінність між цими двома суто умовними умовами: CONSTANTS_ARE_CAPITALIZEDі globals_are_not.

Причина глобальних змінних погана в тому, що вони дозволяють функціям мати приховані (не очевидні, дивовижні, важко виявити, важко діагностувати) побічні ефекти, що призводить до збільшення складності, що потенційно призводить до коду спагетті .

Однак розумне використання глобального стану є прийнятним (як і локальний стан та змінність) навіть у функціональному програмуванні, або для оптимізації алгоритмів, зменшення складності, кешування та запам'ятовування, або практичності перенесення структур, що походять з переважно імперативної бази даних.

Загалом, на ваше запитання можна відповісти різними способами, тож найкраще ставити на гугл, "чому глобальні змінні погані". Деякі приклади:

Якщо ви хочете піти глибше і з'ясувати, чому виникають побічні ефекти, та багато інших освічуючих речей, вам слід вивчити функціональне програмування:


35

Так, теоретично глобалісти (і «держава» взагалі) - це зло. На практиці, якщо ви заглянете в каталог пакунків вашого python, ви побачите, що більшість модулів там починаються з купки глобальних декларацій. Очевидно, що у людей з ними немає проблем.

Зокрема, щодо python, видимість глобалів обмежена модулем, тому немає "справжніх" глобальних глобалів, які впливають на всю програму - це робить їх спосіб менш шкідливим. Ще один момент: таких немає const, тому коли вам потрібна константа, ви повинні використовувати глобальну.

У своїй практиці, якщо мені трапляється модифікувати глобальну функцію, я завжди декларую це global, навіть якщо в цьому технічно немає потреби, як у:

cache = {}

def foo(args):
    global cache

    cache[args] = ...

Це полегшує відстеження маніпуляцій глобалів.


3
багато в чому модуль в python схожий на однотонний клас, а глобальні модулі схожі на властивості класу.
Корлі Бригман

9
@CorleyBrigman: Однокласні заняття насправді часто страждають від тих же проблем, які зазвичай приписуються глобалістам :)
Ерік Каплун

4
видимість модулів python не обмежується модулем. Вони доступні у всьому перекладачі, і (тут важливо) зміни там впливають на весь перекладач. Це не так, як рядок, який ви створюєте екземпляри ... це як зміна всіх екземплярів рядків. Пахучий пахучий запах.
graffic

2
Більшість модулів не починається з визначення глобальних, крім констант. Глобали - це погані значення змінних / глобальний стан, а не константи.
BlackJack

2
Використання глобальних мереж - жахлива ідея, однією з причин може бути неможливість належного тестування функцій, що оновлюють якийсь довільний словник, який існує "десь". Кодова база з глобалами не може бути фактично підтвердженою функціональністю.
Томаш Сосінський

10

Особиста думка з цього приводу полягає в тому, що використання глобальних змінних, що використовуються в логіці функції, означає, що якийсь інший код може змінити логіку та очікуваний вихід цієї функції, що зробить налагодження дуже важким (особливо у великих проектах) і зробить тестування складніше також.

Крім того, якщо ви вважаєте, що інші люди читають ваш код (спільнота з відкритим кодом, колеги тощо), їм буде важко намагатися зрозуміти, де встановлюється глобальна змінна, де була змінена і що чекати від цієї глобальної змінної на противагу до ізольованої функції, її функціональність можна визначити, прочитавши саме визначення функції.

(Можливо) Порушення визначення чистої функції

Я вважаю, що чистий і (майже) код помилок повинен мати максимально чисті функції (див. Чисті функції ). Чистою функцією є та, яка має такі умови:

  1. Функція завжди оцінює одне і те ж значення результату, задаючи однакові значення аргументів . Значення результату функції не може залежати від будь-якої прихованої інформації або стану, яка може змінюватися під час виконання програми або між різними виконанням програми, а також не може залежати від зовнішнього вводу пристроїв вводу-виводу (як правило, див. Нижче).
  2. Оцінка результату не спричиняє жодних семантично помітних побічних ефектів або результатів , таких як мутація змінних об'єктів або вихід на пристрої вводу / виводу.

Наявність глобальних змінних є порушенням принаймні одного з вищезазначених, якщо не обидва, так як зовнішній код, ймовірно, може призвести до несподіваних результатів.

Ще одне чітке визначення чистих функцій: "Чиста функція - це функція, яка приймає всі свої вхідні дані як явні аргументи і виробляє всі її результати як явні результати ". [1] . Наявність глобальних змінних порушує уявлення про чисті функції, оскільки вхід і, можливо, один із виходів (глобальна змінна) явно не надається і не повертається.

(Можливо) Порушення принципу ПЕРШОГО тестування

Далі, якщо ви врахуєте тестування одиниць і ПЕРШИЙ принцип ( F ast тести, I незалежні тести, R epeatable, S elf-Validating та T imely), ймовірно, будуть порушувати принцип Незалежних тестів (це означає, що тести не залежать від один на одного).

Мати глобальну змінну (не завжди), але в більшості випадків (принаймні, що я бачив до цього часу) - це готувати та передавати результати іншим функціям. Це також порушує цей принцип. Якщо глобальна змінна була використана таким чином (тобто глобальна змінна, яка використовується у функції X спочатку повинна бути встановлена ​​у функції Y), це означає, що для одиниці тестової функції X потрібно спочатку запустити функцію тесту / запуску Y.

Глобали як константи

З іншого боку, як вже згадували інші люди, якщо глобальна змінна використовується як "константа" змінної, може бути трохи краще, оскільки мова не підтримує константи. Однак я завжди вважаю за краще працювати з класами і мати "константи" як члена класу, а не використовувати глобальну змінну взагалі. Якщо у вас є код, який потрібен двом різним класам для спільної глобальної змінної, вам, ймовірно, потрібно переробити рішення і зробити класи незалежними.

Я не вірю, що глобали не слід використовувати. Але якщо вони будуть використані, автори повинні врахувати деякі принципи (можливо, згадані вище, а також інші принципи інженерії програмного забезпечення та належну практику) для отримання більш чистого та майже помилкового коду.


1
Мені подобається, що "глобали як константи - це проблема" ... тому що якщо ти займаєшся дизайном ОО ... це насправді так. Чому хтось, крім класу IdCreator, повинен знати ID_LEN?
Ерік Аронесті

3

Вони важливі, екран є хорошим прикладом. Однак у багатопотоковому середовищі або із залученням багатьох розробників на практиці часто виникає питання: хто (помилково) встановив чи очистив це? Залежно від архітектури, аналіз може бути дорогим і вимагати часто. Під час читання глобального var може бути нормальним, запис у нього повинен контролюватися, наприклад, одним потоком або безпечним класом потоку. Отже, у глобальній варі виникає страх перед високими витратами на розвиток, можливими наслідками, які самі вважаються злими. Тому в цілому, це хороша практика, щоб кількість глобальних варіантів залишалася низькою.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.