Я пытаюсь выяснить, почему использование global считается плохой практикой в python (и в программировании в целом). Кто-нибудь может объяснить? Ссылки с дополнительной информацией также были бы оценены.
Переведено автоматически
Ответ 1
Это не имеет ничего общего с Python; глобальные переменные плохи в любом языке программирования.
Однако глобальные константы концептуально не совпадают с глобальными переменными; глобальные константы совершенно безвредны. В Python различие между ними чисто условное: CONSTANTS_ARE_CAPITALIZED и globals_are_not.
Причина, по которой глобальные переменные плохи, заключается в том, что они позволяют функциям иметь скрытые (неочевидные, неожиданные, трудно обнаруживаемые, трудно диагностируемые) побочные эффекты, приводящие к увеличению сложности, потенциально приводящие к спагетти-коду.
Однако разумное использование глобального состояния приемлемо (как и локального состояния и изменчивости) даже в функциональном программировании, либо для оптимизации алгоритмов, снижения сложности, кэширования и запоминания, либо для практичности переноса структур, происходящих из преимущественно императивной кодовой базы.
В общем, на ваш вопрос можно ответить по-разному, поэтому лучше всего просто погуглить "почему глобальные переменные плохие". Несколько примеров:
Если вы хотите углубиться и выяснить, зачем нужны побочные эффекты, и многие другие полезные вещи, вам следует изучить функциональное программирование:
Да, в теории глобальные переменные (и "состояние" в целом) являются злом. На практике, если вы заглянете в каталог пакетов вашего python, вы обнаружите, что большинство модулей там начинаются с набора глобальных объявлений. Очевидно, что у людей с ними нет проблем.
Конкретно для python видимость глобальных переменных ограничена модулем, поэтому не существует "истинных" глобальных переменных, которые влияют на всю программу - это делает их менее вредными. Еще один момент: их нет const, поэтому, когда вам нужна константа, вы должны использовать глобальную.
В моей практике, если мне случается изменить глобальные переменные в функции, я всегда объявляю это с помощью global, даже если технически в этом нет необходимости, как в:
cache = {}
deffoo(args): global cache
cache[args] = ...
Это упрощает отслеживание манипуляций глобалами.
Ответ 3
Личное мнение по этому поводу таково, что использование глобальных переменных в логике функции означает, что какой-то другой код может изменить логику и ожидаемый результат этой функции, что очень усложнит отладку (особенно в больших проектах), а также усложнит тестирование.
Более того, если вы считаете, что другие люди читают ваш код (сообщество с открытым исходным кодом, коллеги и т.д.), Им будет трудно понять, где устанавливается глобальная переменная, где были внесены изменения и чего ожидать от этой глобальной переменной в отличие от изолированной функции, функциональность которой можно определить, прочитав само определение функции.
(Вероятно) Нарушает определение чистой функции
Я считаю, что чистый и (почти) не содержащий ошибок код должен содержать функции, которые являются максимально чистыми (см. Чистые функции ). Чистая функция - это та, которая выполняет следующие условия:
Функция всегда вычисляет одно и то же результирующее значение при одинаковых значениях аргументов. Результирующее значение функции не может зависеть от какой-либо скрытой информации или состояния, которые могут изменяться во время выполнения программы или между различными исполнениями программы, а также не может зависеть от какого-либо внешнего ввода от устройств ввода-вывода (обычно — см. Ниже).
Оценка результата не вызывает никаких семантически наблюдаемых побочных эффектов или выходных данных, таких как мутация изменяемых объектов или вывод на устройства ввода-вывода.
Наличие глобальных переменных нарушает по крайней мере одно из вышеперечисленных, если не оба, поскольку внешний код, вероятно, может привести к неожиданным результатам.
Еще одно четкое определение чистых функций: "Чистая функция - это функция, которая принимает все свои входные данные в качестве явных аргументов и выдает все свои выходные данные в виде явных результатов". [1]. Наличие глобальных переменных нарушает идею чистых функций, поскольку входные данные и, возможно, один из выходных данных (глобальная переменная) явно не передаются и не возвращаются.
(Вероятно) Нарушает принцип F.I.R.S.T. модульного тестирования
Далее, если вы рассматриваете модульное тестирование и принцип F.I.R.S.T. (Fast-тесты, Iнезависимые тесты, Rдопустимый, S elf-валидация и Timely), вероятно, нарушат принцип независимых тестов (что означает, что тесты не зависят друг от друга).
Наличие глобальной переменной (не всегда), но в большинстве случаев (по крайней мере, из тех, что я видел до сих пор) предназначено для подготовки и передачи результатов другим функциям. Это также нарушает этот принцип. Если глобальная переменная использовалась таким образом (т. е. Глобальная переменная, используемая в функции X, должна быть сначала установлена в функции Y), это означает, что для модульного тестирования функции X вы должны сначала запустить тест / run function Y.
Глобальные переменные как константы
С другой стороны, как уже упоминали другие люди, если глобальная переменная используется как "постоянная", переменная может быть немного лучше, поскольку язык не поддерживает константы. Однако я всегда предпочитаю работать с классами и иметь "константы" в качестве члена класса и вообще не использовать глобальную переменную. Если у вас есть код, который требуется двум разным классам для совместного использования глобальной переменной, то вам, вероятно, необходимо провести рефакторинг вашего решения и сделать ваши классы независимыми.
Я не верю, что глобальные переменные не следует использовать. Но если они используются, авторам следует учитывать некоторые принципы (возможно, упомянутые выше, а также другие принципы разработки программного обеспечения и передовые практики) для получения более чистого и почти безошибочного кода.
Ответ 4
Они необходимы, хорошим примером является экран. Однако в многопоточной среде или при участии многих разработчиков на практике часто возникает вопрос: кто (по ошибке) установил или очистил это? В зависимости от архитектуры анализ может быть дорогостоящим и требоваться часто. Хотя чтение глобального var может быть нормальным, запись в него должна контролироваться, например, одним потоком или threadsafe классом. Следовательно, глобальные переменные вызывают страх перед возможными высокими затратами на разработку из-за последствий, которые сами по себе считаются злом. Следовательно, в целом, хорошей практикой является поддержание низкого количества глобальных переменных.