Почему глобальные переменные являются злом?
Я пытался найти хороший источник, который объясняет, почему использование global
считается плохой практикой в питоне (и в программировании в целом). Может кто-нибудь указать мне на один или объяснить здесь?
4 ответа
Это не имеет ничего общего с Python; глобальные переменные плохи в любом языке программирования.
Однако глобальные константы концептуально не совпадают с глобальными переменными; Глобальные константы идеально подходят для использования. Просто в Python нет синтаксической разницы.
Причина, по которой они плохи, заключается в том, что они позволяют функциям скрывать (как в "неочевидных" и "необъявленных") и, таким образом, трудно понять побочные эффекты. Кроме того, это может привести к коду спагетти.
Кроме того, допустимо ограниченное / контролируемое / сознательное использование глобальных переменных, так же как локальное состояние, то есть изменяемые переменные, допустимо в функциональном программировании либо по соображениям производительности, либо для простоты, либо для кэширования / запоминания.
Но, конечно, на ваш вопрос есть много ответов, поэтому вам лучше всего просто спросить "почему глобальные переменные плохие". Некоторые примеры:
- http://c2.com/cgi/wiki?GlobalVariablesAreBad
- https://softwareengineering.stackexchange.com/questions/148108/why-is-global-state-so-evil
- Являются ли глобальные переменные плохими?
Если вы хотите пойти глубже и выяснить, для чего нужны побочные эффекты и многое другое, вы должны изучить функциональное программирование:
Да, в теории глобалы (и "государство" в целом) являются злом. На практике, если вы загляните в каталог пакетов вашего python, то обнаружите, что большинство модулей там начинаются с нескольких глобальных объявлений. Очевидно, у людей нет проблем с ними.
В частности, для Python видимость глобалов ограничена модулем, поэтому нет "настоящих" глобалов, которые влияют на всю программу, что делает их менее вредными. Еще один момент: нет const
, поэтому, когда вам нужна константа, вы должны использовать глобальный.
В моей практике, если мне случается изменить глобал в функции, я всегда объявляю это с global
, даже если в этом нет технической необходимости, например:
cache = {}
def foo(args):
global cache
cache[args] = ...
Это облегчает отслеживание манипуляций глобалов.
Личное мнение по этому вопросу заключается в том, что использование глобальных переменных в логике функции означает, что некоторый другой код может изменить логику и ожидаемый результат этой функции, что сделает отладку очень сложной (особенно в больших проектах) и усложнит тестирование. также.
Кроме того, если вы считаете, что другие люди читают ваш код (сообщество с открытым исходным кодом, коллеги и т. Д.), Им будет трудно понять, где задается глобальная переменная, где она была изменена и что ожидать от этой глобальной переменной в противоположность для изолированной функции, что ее функциональность может быть определена путем чтения самого определения функции.
(Возможно) нарушение определения чистой функции
Я считаю, что чистый и (почти) безошибочный код должен иметь как можно более чистые функции(см." Чистые функции"). Чистая функция - это та, которая имеет следующие условия:
- Функциявсегда оценивает одно и то же значение результата, учитывая одно и то же значение аргумента. Значение результата функции не может зависеть от какой-либо скрытой информации или состояния, которые могут изменяться во время выполнения программы или между различными выполнениями программы, а также не может зависеть от какого-либо внешнего ввода от устройств ввода-вывода (обычно - см. Ниже).
- Оценка результатане вызывает какого-либо семантически наблюдаемого побочного эффекта или вывода, такого как мутация изменяемых объектов или вывод на устройства ввода-вывода.
Наличие глобальных переменных нарушает, по крайней мере, одно из вышеперечисленного, если не оба, поскольку внешний код может привести к неожиданным результатам.
Другое четкое определение чистых функций: "Чистая функция - это функция, которая принимает все свои входные данные как явные аргументы и производит все свои выходные данные как явные результаты". [1]. Наличие глобальных переменных нарушает идею чистых функций, поскольку входные данные и, возможно, один из выходных данных (глобальная переменная) явно не передаются или не возвращаются.
(Вероятно) Нарушение модульного тестирования ПЕРВЫЙ принцип
Далее, если вы рассмотрите модульное тестирование и принцип FIRST (F ast тесты, независимые тесты, R epeatable, S elf-Validating и T imely), вероятно, нарушит принцип независимых тестов (что означает, что тесты не зависят друг на друга).
Наличие глобальной переменной (не всегда), но в большинстве случаев (по крайней мере, из того, что я видел до сих пор) - это подготовка и передача результатов другим функциям. Это также нарушает этот принцип. Если глобальная переменная использовалась таким образом (то есть глобальная переменная, используемая в функции X, должна быть сначала установлена в функции Y), это означает, что для модульного тестирования функции X сначала необходимо запустить функцию test / run Y.
Глобалы как константы
С другой стороны, и как уже упоминали другие люди, если глобальная переменная используется в качестве "постоянной", переменная может быть немного лучше, поскольку язык не поддерживает константы. Однако я всегда предпочитаю работать с классами и иметь "константы" в качестве члена класса и вообще не использовать глобальную переменную. Если у вас есть код, который требуется двум разным классам для общего доступа к глобальной переменной, вам, вероятно, потребуется реорганизовать решение и сделать ваши классы независимыми.
Я не верю, что глобалы не должны использоваться. Но если они используются, авторы должны рассмотреть некоторые принципы (возможно, упомянутые выше, а также другие принципы разработки программного обеспечения и передовые практики) для более чистого и почти безошибочного кода.
Они важны, экран является хорошим примером. Однако в многопоточной среде или с участием многих разработчиков на практике часто возникает вопрос: кто (ошибочно) установил или очистил это? В зависимости от архитектуры анализ может быть дорогостоящим и часто требоваться. Хотя чтение глобальной переменной может быть в порядке, запись в нее должна контролироваться, например, одним потоком или потокобезопасным классом. Следовательно, глобальные перемены порождают страх высоких затрат на разработку, возможный из-за последствий, которые сами по себе считаются злом. Поэтому в общем случае хорошей практикой является сохранение количества глобальных переменных на низком уровне.