Вопрос

Тот Самый __debug__ переменная удобна отчасти потому, что она влияет на каждый модуль.Если я хочу создать другую переменную, которая работает таким же образом, как бы я это сделал?

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

Это было полезно?

Решение

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

a.py содержит

print foo

b.py содержит

import __builtin__
__builtin__.foo = 1
import a

В результате выводится цифра "1".

Редактировать: Тот Самый __builtin__ модуль доступен в качестве локального символа __builtins__ -- вот в чем причина расхождения между двумя этими ответами.Также обратите внимание, что __builtin__ был переименован в builtins в python3.

Другие советы

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

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

Пример из реального мира: Джанго global_settings.py (хотя в Django настройки приложений используются при импорте объект django.conf.settings).

Определите модуль ( назовите его "globalbaz") и определите переменные внутри него.Все модули, использующие этот "псевдоглобальный" модуль, должны импортировать модуль "globalbaz" и ссылаться на него, используя "globalbaz.var_name"

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

Для пояснения, globalbaz.py выглядит примерно так:

var_name = "my_useful_string"

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

Когда есть только один такой модуль, я называю его "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), чтобы обнаружить любые неожиданные названия, которые могли возникнуть в результате такой случайности.

Вы можете передать глобальные значения одного модуля другому:

В Модуле А:

import module_b
my_var=2
module_b.do_something_with_my_globals(globals())
print my_var

В Модуле В:

def do_something_with_my_globals(glob): # glob is simply a dict.
    glob["my_var"]=3

Глобальные переменные обычно являются плохой идеей, но вы можете сделать это, присвоив __builtins__:

__builtins__.foo = 'something'
print foo

Кроме того, сами модули являются переменными, к которым вы можете получить доступ из любого модуля.Итак, если вы определяете модуль, называемый my_globals.py:

# my_globals.py
foo = 'something'

Тогда вы также можете использовать это из любого места:

import my_globals
print my_globals.foo

Использование модулей, а не изменение __builtins__ как правило, это более чистый способ выполнения глобальных операций такого рода.

Вы уже можете сделать это с помощью переменных уровня модуля.Модули одинаковы независимо от того, из какого модуля они импортируются.Таким образом, вы можете сделать переменную переменной уровня модуля в любом модуле, в который имеет смысл ее поместить, и получить к ней доступ или назначить ей назначение из других модулей.Было бы лучше вызвать функцию для установки значения переменной или сделать ее свойством какого-нибудь одноэлементного объекта.Таким образом, если вам в конечном итоге понадобится запустить какой-то код при изменении переменной, вы можете сделать это, не нарушая внешний интерфейс вашего модуля.

Обычно это не самый лучший способ делать что—либо — использование глобальных файлов встречается редко, - но я думаю, что это самый чистый способ сделать это.

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

Циклический импорт может нарушить поведение модуля.

Например:

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

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

Это звучит как изменение __builtin__ пробел в имени.Чтобы сделать это:

import __builtin__
__builtin__.foo = 'some-value'

Не используйте __builtins__ напрямую (обратите внимание на лишнюю букву "s") - по-видимому, это может быть словарь или модуль.Благодаря ΤΖΩΤΖΙΟΥ за указание на это, можно найти больше здесь.

Сейчас foo доступен для использования везде.

Я не рекомендую делать это обычно, но использование этого зависит от программиста.

Присвоение ему должно быть выполнено, как описано выше, просто установив foo = 'some-other-value' будет установлено только в текущем пространстве имен.

Я использую это для пары встроенных примитивных функций, которых, по моему мнению, действительно не хватало.Одним из примеров является функция find, которая имеет ту же семантику использования, что и 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.

Примечание: Вы можете сделать это, конечно, с помощью filter и другой строки для проверки на нулевую длину или с помощью reduce в одной какой-то странной строке, но мне всегда казалось, что это странно.

Я мог бы добиться межмодульной модификации (или изменяемый) переменные с помощью словаря:

# 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 секунды.

Я задавался вопросом, можно ли было бы избежать некоторых недостатков использования глобальных переменных (см., например, 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

Этот модуль импортирует wall и определяет единственную функцию 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 больше не существует.

Результатом работы программы является:

глобальный:Привет, мир!
маршрутизатор:Привет, мир!
глобальный:никакого сообщения
маршрутизатор:никакого сообщения

Приведенные выше фрагменты кода показывают, что механизмы module /global и class /class variable по существу идентичны.

Если необходимо совместно использовать множество переменных, загрязнением пространства имен можно управлять либо с помощью нескольких модулей типа wall, напримерстенка1, стенка2 и т.д.или путем определения нескольких классов типа маршрутизатора в одном файле.Последнее немного опрятнее, поэтому, возможно, представляет собой незначительное преимущество для использования механизма class-variable.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top