Почему глобальные переменные злые?

Я пытался найти хороший источник, объясняющий, почему использование global считается плохой практикой в ​​python (и вообще в программировании). Может ли кто-нибудь указать мне на это или объяснить здесь?

Ответ 1

Это не имеет ничего общего с Python; глобальные переменные плохи в любом языке программирования.

Однако глобальные константы концептуально не совпадают с глобальными переменными; глобальные константы совершенно безвредны. Просто в Python нет принудительного различия, только условно CONSTANTS_CAPITALIZED и globals_are_not.

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

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

В общем, на ваш вопрос можно ответить разными способами, поэтому вам лучше всего просто спросить "почему плохие глобальные переменные". Некоторые примеры:

Если вы хотите пойти глубже и выяснить, для чего нужны побочные эффекты и многое другое, вы должны изучить функциональное программирование:

Ответ 2

Да, теоретически глобальные (и вообще "государственные" ) являются злыми. На практике, если вы заглянете в свой каталог пакетов python, вы обнаружите, что большинство модулей там начинается с кучи глобальных объявлений. Очевидно, что у людей нет проблем с ними.

В частности, для python видимость globals ограничена модулем, поэтому не существует "истинных" глобальных переменных, которые влияют на всю программу, что делает их менее вредными. Другой момент: нет const, поэтому, когда вам нужна константа, вы должны использовать глобальную.

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

cache = {}

def foo(args):
    global cache

    cache[args] = ...

Это облегчает отслеживание манипуляций с глобалами.

Ответ 3

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

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

(Возможно) нарушение определения чистой функции

Я считаю, что чистый и (почти) безошибочный код должен иметь как можно более чистые функции (см. " Чистые функции"). Чистая функция - это та, которая имеет следующие условия:

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

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

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

(Вероятно) Нарушение модульного тестирования ПЕРВЫЙ принцип

Далее, что, если вы считаете, юнит-тестирование и первый принцип (F испытания AST, я ndependent тесты, R epeatable, S-эльф Validating и Т imely), вероятно, нарушают Независимые тесты принцип (что означает, что тесты не зависят друг на друга).

Наличие глобальной переменной (не всегда), но в большинстве случаев (по крайней мере, из того, что я видел до сих пор) является подготовкой и передачей результатов другим функциям. Это также нарушает этот принцип. Если глобальная переменная использовалась таким образом (то есть глобальная переменная, используемая в функции X, должна быть сначала задана в функции Y), это означает, что для модульного тестирования функции X вы должны сначала запустить функцию test/run Y.

Глобалы как константы

С другой стороны, и как уже упоминали другие люди, если глобальная переменная используется как "постоянная", переменная может быть немного лучше, поскольку язык не поддерживает константы. Однако я всегда предпочитаю работать с классами и иметь "константы" в качестве члена класса и вообще не использовать глобальную переменную. Если у вас есть код, который требуется двум разным классам для общего доступа к глобальной переменной, вам, вероятно, потребуется реорганизовать решение и сделать ваши классы независимыми.

Я не верю, что глобалы не должны использоваться. Но если они используются, авторы должны рассмотреть некоторые принципы (возможно, упомянутые выше, а также другие принципы разработки программного обеспечения и передовые практики) для более чистого и почти безошибочного кода.

Ответ 4

Они важны, экран является хорошим примером. Однако в многопоточной среде или с участием многих разработчиков на практике часто возникает вопрос: кто (ошибочно) установил или очистил это? В зависимости от архитектуры анализ может быть дорогостоящим и часто требоваться. Хотя чтение глобальной переменной может быть в порядке, запись в нее должна контролироваться, например, одним потоком или потокобезопасным классом. Следовательно, глобальные перемены порождают страх высоких затрат на разработку, возможный из-за последствий, которые сами по себе считаются злом. Поэтому, в целом, рекомендуется поддерживать число глобальных переменных на низком уровне.