Видимость глобальных переменных в импортируемых модулях

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

предположим, у меня есть модуль, в котором я определил некоторые функции/классы утилиты, которые относятся к сущностям, определенным в пространстве имен, в которое будет импортирован этот вспомогательный модуль (пусть "a" будет таким entity):

модуль1:

def f():
    print a

и тогда у меня есть основная программа, где определяется "a", в которую я хочу импортировать эти утилиты:

import module1
a=3
module1.f()

выполнение программы вызовет следующую ошибку:

Traceback (most recent call last):
  File "Z:Pythonmain.py", line 10, in <module>
    module1.f()
  File "Z:Pythonmodule1.py", line 3, in f
    print a
NameError: global name 'a' is not defined

подобные вопросы были заданы в прошлом (два дня назад, d'UH) и было предложено несколько решений, однако я не думаю, что они соответствуют моим требованиям. вот мой конкретный контекст:

Я пытаюсь сделать программу Python, которая подключается к серверу баз данных MySQL и отображает/изменяет данные с помощью GUI. Для чистоты я определил кучу вспомогательных / утилитарных функций, связанных с MySQL, в отдельном файле. Однако все они имеют общую переменную, которую я изначально определил внутри модуль утилиты, и который является курсор объект из модуля MySQLdb. Позже я понял, что курсор объект (который используется для связи с сервером БД) должен быть определен в основном модуле, чтобы и основной модуль, и все, что импортируется в него, могли получить доступ к этому объекту.

конечный результат будет примерно таким:

utilities_module.py:

def utility_1(args):
    code which references a variable named "cur"
def utility_n(args):
    etcetera

и мой основной модуль:

program.py:

import MySQLdb, Tkinter
db=MySQLdb.connect(#blahblah) ; cur=db.cursor()  #cur is defined!
from utilities_module import *

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

особое предложение состояло в том, чтобы иметь оператор "from program import cur" в файле утилит, например:

utilities_module.py:

from program import cur
#rest of function definitions

program.py:

import Tkinter, MySQLdb
db=MySQLdb.connect(#blahblah) ; cur=db.cursor()  #cur is defined!
from utilities_module import *

но это циклический импорт или что-то в этом роде, и, в конечном итоге, он тоже падает. Поэтому мой вопрос:

как, черт возьми, я могу сделать объект" cur", определенный в основном модуле, видимым к тем вспомогательным функциям, которые в него импортируются?

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

6 ответов


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

есть разные способы решить эту проблему, в зависимости от вашего фактического случая использования.


прежде чем даже идти по этому пути, спросите себя, действительно ли это должно быть глобальным. Может быть, вы действительно хотите класс, с f как метод экземпляра, а не просто бесплатно работать? Затем вы могли бы сделать что-то вроде этого:

import module1
thingy1 = module1.Thingy(a=3)
thingy1.f()

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

import module1
module1.a=3
module1.f()

С другой стороны, если a разделяется целым рядом модулей, поместите его где-нибудь еще, и все импортируют его:

import shared_stuff
import module1
shared_stuff.a = 3
module1.f()

... и, в module1.py:

import shared_stuff
def f():
    print shared_stuff.a

не используйте from импорт, если переменная не предназначена для константы. from shared_stuff import a создать новый a переменная инициализирована в whatever shared_stuff.a упоминается во время импорта, и это новое a переменная не будет влиять поручения shared_stuff.a.


или, в редком случае, вам действительно нужно, чтобы он был действительно глобальным везде, как встроенный, добавьте его в встроенный модуль. Точные детали отличаются между Python 2.x и 3.х. В 3.x, это работает вот так:

import builtins
import module1
builtins.a = 3
module1.f()

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

main.py:

import os
os.environ['MYVAL'] = str(myintvariable)

mymodule.py:

import os
print os.environ['MYVAL']

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


функция использует глобалы модуля, это определена in. Вместо установки a = 3, например, вы должны быть module1.a = 3. Итак, если вы хотите cur доступен как глобальный в utilities_module, set utilities_module.cur.

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


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

а именно, у меня есть модуль, который содержит глобальные/общие переменные (как предлагалось выше):

#sharedstuff.py

globaltimes_randomnode=[]
globalist_randomnode=[]

тогда у меня был основной модуль, который импортирует общий материал с:

import sharedstuff as shared

и некоторые другие модули, которые фактически населяли эти массивы. Они вызываются главным модулем. Когда выходя из этих других модулей, я ясно вижу, что массивы заполнены. Но когда я читал их в главном модуле, они были пусты. Это было довольно странно для меня (ну, я новичок в Python). Однако, когда я изменяю способ импорта sharedstuff.py в главном модуле:

from globals import *

он работал (массивы были заселены).

просто sayin'


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

модуль1:

cursor = None

def setCursor(cur):
    global cursor
    cursor = cur

def method(some, args):
    global cursor
    do_stuff(cursor, some, args)

основная программа:

import module1

cursor = get_a_cursor()
module1.setCursor(cursor)
module1.method()

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

  • добавить сингулярные переменные (в формате словаря) в качестве глобалов для тех
  • передачи main глобалы модуля к нему .

addglobals = lambda x: globals().update (x)

тогда все, что вам нужно передать на текущих глобалах:

импорт модуль

модуль.addglobals (globals ())