Переменная __debug__ удобна отчасти потому, что она влияет на каждый модуль. Если я хочу создать другую переменную, которая работает таким же образом, как бы я это сделал?
Переменная (давайте будем оригинальными и назовем ее «foo») не обязательно должна быть по-настоящему глобальной, в том смысле, что если я изменю foo в одном модуле, он обновится в других. Было бы хорошо, если бы я мог установить foo перед импортом других модулей, и тогда они увидели бы для него то же значение.






Похоже на изменение пространства имен __builtin__. Сделать это:
import __builtin__
__builtin__.foo = 'some-value'
Не используйте __builtins__ напрямую (обратите внимание на дополнительные "s") - очевидно, это может быть словарь или модуль. Благодаря ΩΤΖΙΟΥ за указание на это можно найти больше здесь.
Теперь foo доступен для использования повсюду.
Обычно я не рекомендую делать это, но использование этого остается на усмотрение программиста.
Назначение для него должно быть выполнено, как указано выше, просто установка foo = 'some-other-value' установит его только в текущем пространстве имен.
Я никоим образом не поддерживаю это решение. Но если вы добавите переменную в модуль __builtin__, она будет доступна как глобальная из любого другого модуля, который включает __builtin__ - а это все они по умолчанию.
a.py содержит
print foo
b.py содержит
import __builtin__
__builtin__.foo = 1
import a
В результате печатается «1».
Редактировать: Модуль __builtin__ доступен как локальный символ __builtins__ - это причина расхождения между двумя из этих ответов. Также обратите внимание, что __builtin__ был переименован в builtins в python3.
Есть ли причина, по которой вам не нравится эта ситуация?
Во-первых, это разбивает ожидания людей, когда они читают код. «Что это за символ« foo »? Почему я не вижу, где он определен?»
Он также может нанести серьезный ущерб, если будущая версия Python начнет использовать выбранное вами имя как фактическую встроенную команду.
Это хорошее решение для таких вещей, как совместное использование db-соединения с импортированными модулями. В качестве проверки работоспособности я убеждаюсь, что импортированный модуль утверждает hasattr(__builtin__, "foo").
Я бы рекомендовал удалить импортный __builtin__ и просто использовать __builtins__
Это также хорошее решение, если вы хотите создать какой-то уровень совместимости между питонами - например, вы можете использовать type для создания нового типа и переопределения функции type таким образом, чтобы в Python <3 он автоматически наследовался от объекта.
Ноно, это именно то, от чего я пытаюсь уйти! Мне нужна указанная переменная с пространством имен, чтобы не касался моего встроенные, чтобы он мог оставаться нетронутым от этого мусора.
Для тех, кто читает этот ответ: НЕ! ДЕЛАТЬ ! ЭТО ! На самом деле, не надо.
@brunodesthuilliers На самом деле есть случаи, когда это удобно :) Например, на ноутбуке IPython, и мы хотим, чтобы какая-то внутренняя функция открывала некоторые переменные глобально, чтобы мы могли поиграть с ней
Определите модуль (назовите его globalbaz) и определите в нем переменные. Все модули, использующие этот «псевдоглобальный», должны импортировать модуль «globalbaz» и ссылаться на него, используя «globalbaz.var_name».
Это работает независимо от места изменения, вы можете изменить переменную до или после импорта. Импортированный модуль будет использовать последнее значение. (Я тестировал это на игрушечном примере)
Для пояснения, globalbaz.py выглядит примерно так:
var_name = "my_useful_string"
Если вам нужна глобальная кросс-модульная переменная, возможно, будет достаточно простой глобальной переменной уровня модуля.
a.py:
var = 1
b.py:
import a
print a.var
import c
print a.var
c.py:
import a
a.var = 2
Тестовое задание:
$ python b.py
# -> 1 2
Реальный пример: Django global_settings.py (хотя в приложениях Django настройки используются путем импорта объектdjango.conf.settings).
Лучше, потому что это позволяет избежать возможных конфликтов пространства имен
Что, если модуль, который вы импортируете, в данном случае a.py, содержит main()? Это имеет значение?
@sedeh: нет. Если a.py также запускается как сценарий, используйте в нем защиту if __name__= = "__main__", чтобы избежать запуска неожиданного кода при импорте.
В реальном мире с этим решением нужно быть немного осторожнее. Если программист выбирает вашу «глобальную» переменную с помощью «from a import var» (попробуйте этот вариант в c.py), он получит копию переменной во время импорта.
@PaulWhipp: неправильный (подсказка: используйте id() для проверки личности)
Шикарное решение! Правильно проголосовали большинство! Лучше, потому что это позволяет избежать возможных конфликтов пространства имен!
@pevogam: нет, import не имеет объектов копировать. Бьюсь об заклад, вы использовали from a import var (var теперь находится в другом пространстве имен) вместо import a, как в моем ответе. (var остается в пространстве имен модуля a). Объект одинаковый, копии в обоих случаях нет. Связанный: Почему в Python функция может изменять одни аргументы, воспринимаемые вызывающей стороной, но не другие?
Уловка: - Я сначала использовал from a import var, а var не было. - заменено на 'import a' и var на a.var, как написано выше, и это сработало!
Глобальные переменные обычно плохая идея, но вы можете сделать это, присвоив __builtins__:
__builtins__.foo = 'something'
print foo
Кроме того, сами модули представляют собой переменные, к которым вы можете получить доступ из любого модуля. Итак, если вы определяете модуль с именем my_globals.py:
# my_globals.py
foo = 'something'
Тогда вы можете использовать это откуда угодно:
import my_globals
print my_globals.foo
Использование модулей вместо модификации __builtins__, как правило, является более чистым способом создания глобальных объектов такого рода.
__builtins__ - это особенность CPython, вам действительно не стоит его использовать - лучше используйте __builtin__ (или builtins в Python3), как показывает принятый ответ
Вы можете передать глобальные объекты одного модуля другому:
В модуле A:
import module_b
my_var=2
module_b.do_something_with_my_globals(globals())
print my_var
В модуле B:
def do_something_with_my_globals(glob): # glob is simply a dict.
glob["my_var"]=3
Вы уже можете сделать это с помощью переменных уровня модуля. Модули одинаковы независимо от того, из какого модуля они импортируются. Таким образом, вы можете сделать переменную переменной уровня модуля в любом модуле, в который имеет смысл поместить ее, и получить к ней доступ или назначить ее из других модулей. Было бы лучше вызвать функцию для установки значения переменной или сделать ее свойством какого-то одноэлементного объекта. Таким образом, если вам в конечном итоге понадобится запустить какой-то код при изменении переменной, вы можете сделать это, не нарушая внешний интерфейс вашего модуля.
Обычно это не лучший способ делать что-то - использование глобальных переменных - редко, - но я думаю, что это самый чистый способ сделать это.
Я использую это для пары встроенных примитивных функций, которых, как мне казалось, действительно не хватало. Одним из примеров является функция поиска, которая имеет ту же семантику использования, что и filter, map, reduce.
def builtin_find(f, x, d=None):
for i in x:
if f(i):
return i
return d
import __builtin__
__builtin__.find = builtin_find
После запуска (например, путем импорта рядом с вашей точкой входа) все ваши модули могут использовать find (), как если бы, очевидно, он был встроен.
find(lambda i: i < 0, [1, 3, 0, -5, -10]) # Yields -5, the first negative.
Примечание: Вы можете сделать это, конечно, с фильтром и другой строкой для проверки нулевой длины или с помощью сокращения в какой-то странной строке, но мне всегда казалось, что это странно.
Я считаю, что существует множество обстоятельств, при которых это имеет смысл и упрощает программирование, имея некоторые глобальные объекты, которые известны в нескольких (тесно связанных) модулях. В этом духе я хотел бы немного остановиться на идее наличия модуля глобальных объектов, который импортируется теми модулями, которым необходимо ссылаться на них.
Когда есть только один такой модуль, я называю его «g». В нем я назначаю значения по умолчанию для каждой переменной, которую собираюсь рассматривать как глобальную. В каждом модуле, который использует любой из них, я не использую «from g import var», так как это приводит только к локальной переменной, которая инициализируется из g только во время импорта. Я делаю большинство ссылок в форме g.var и "g." служит постоянным напоминанием о том, что я имею дело с переменной, которая потенциально доступна другим модулям.
Если значение такой глобальной переменной должно часто использоваться в какой-либо функции в модуле, тогда эта функция может сделать локальную копию: var = g.var. Однако важно понимать, что присвоения var являются локальными, и глобальный g.var не может быть обновлен без явной ссылки на g.var в назначении.
Обратите внимание, что у вас также может быть несколько таких глобальных модулей, совместно используемых разными подмножествами ваших модулей, чтобы держать вещи под более строгим контролем. Причина, по которой я использую короткие имена для своих глобальных модулей, заключается в том, чтобы не перегружать код их вхождениями. Имея лишь небольшой опыт, они становятся достаточно мнемоническими, имея всего 1 или 2 символа.
По-прежнему возможно назначить, скажем, g.x, когда x еще не был определен в g, и тогда другой модуль может получить доступ к g.x. Однако, хотя интерпретатор это позволяет, этот подход не так прозрачен, и я его избегаю. По-прежнему существует вероятность случайного создания новой переменной в g в результате опечатки в имени переменной для присвоения. Иногда изучение dir (g) полезно для обнаружения каких-либо неожиданных имен, которые могли возникнуть в результате такой случайности.
Это интересное наблюдение решило мою проблему: «Я не использую« from g import var », так как это приводит только к локальной переменной, которая инициализируется из g только во время импорта». Кажется разумным предположить, что «from..import» - это то же самое, что «import», но это неверно.
Я мог бы получить переменные, изменяемые между модулями (или изменчивый), используя словарь:
# in myapp.__init__
Timeouts = {} # cross-modules global mutable variables for testing purpose
Timeouts['WAIT_APP_UP_IN_SECONDS'] = 60
# in myapp.mod1
from myapp import Timeouts
def wait_app_up(project_name, port):
# wait for app until Timeouts['WAIT_APP_UP_IN_SECONDS']
# ...
# in myapp.test.test_mod1
from myapp import Timeouts
def test_wait_app_up_fail(self):
timeout_bak = Timeouts['WAIT_APP_UP_IN_SECONDS']
Timeouts['WAIT_APP_UP_IN_SECONDS'] = 3
with self.assertRaises(hlp.TimeoutException) as cm:
wait_app_up(PROJECT_NAME, PROJECT_PORT)
self.assertEqual("Timeout while waiting for App to start", str(cm.exception))
Timeouts['WAIT_JENKINS_UP_TIMEOUT_IN_SECONDS'] = timeout_bak
При запуске test_wait_app_up_fail фактическая продолжительность тайм-аута составляет 3 секунды.
Я хотел опубликовать ответ, что есть случай, когда переменная не будет найдена.
Циклический импорт может нарушить работу модуля.
Например:
first.py
import second
var = 1
second.py
import first
print(first.var) # will throw an error because the order of execution happens before var gets declared.
main.py
import first
В этом примере это должно быть очевидно, но в большой кодовой базе это может сбивать с толку.
Мне было интересно, можно ли избежать некоторых недостатков использования глобальных переменных (см., Например, http://wiki.c2.com/?GlobalVariablesAreBad), используя пространство имен классов, а не пространство имен глобального / модуля для передачи значений переменных. Следующий код указывает на то, что эти два метода практически идентичны. Как поясняется ниже, использование пространств имен классов дает небольшое преимущество.
Следующие фрагменты кода также показывают, что атрибуты или переменные могут быть динамически созданы и удалены как в глобальных пространствах имен / модулей, так и в пространствах имен классов.
wall.py
# Note no definition of global variables
class router:
""" Empty class """
Я называю этот модуль «стеной», поскольку он используется для отражения переменных. Он будет действовать как пространство для временного определения глобальных переменных и общеклассовых атрибутов пустого класса «router».
source.py
import wall
def sourcefn():
msg = 'Hello world!'
wall.msg = msg
wall.router.msg = msg
Этот модуль импортирует стену и определяет единственную функцию sourcefn, которая определяет сообщение и передает его с помощью двух разных механизмов, одного через глобальные переменные, а другого через функцию маршрутизатора. Обратите внимание, что переменные wall.msg и wall.router.message впервые определены здесь в своих соответствующих пространствах имен.
dest.py
import wall
def destfn():
if hasattr(wall, 'msg'):
print 'global: ' + wall.msg
del wall.msg
else:
print 'global: ' + 'no message'
if hasattr(wall.router, 'msg'):
print 'router: ' + wall.router.msg
del wall.router.msg
else:
print 'router: ' + 'no message'
Этот модуль определяет функцию destfn, которая использует два разных механизма для получения сообщений, отправленных источником. Это допускает возможность того, что переменная msg может не существовать. destfn также удаляет переменные после того, как они были отображены.
main.py
import source, dest
source.sourcefn()
dest.destfn() # variables deleted after this call
dest.destfn()
Этот модуль последовательно вызывает ранее определенные функции. После первого вызова dest.destfn переменные wall.msg и wall.router.msg больше не существуют.
Вывод программы:
global: Привет, мир!
роутер: Привет, мир!
global: нет сообщения
маршрутизатор: нет сообщения
Приведенные выше фрагменты кода показывают, что механизмы переменных модуль / глобальный и класс / класс по существу идентичны.
Если необходимо совместное использование большого количества переменных, загрязнением пространства имен можно управлять либо с помощью нескольких модулей настенного типа, например wall1, wall2 и т. д. или путем определения нескольких классов типа маршрутизатора в одном файле. Последнее немного аккуратнее, поэтому, возможно, представляет собой незначительное преимущество для использования механизма переменных классов.
Я помню (из comp.lang.python), что следует избегать прямого использования встроенные; вместо этого импортируйте встроенный и используйте его, как предложил Курт Хагенлохер.