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

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

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

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

module1:

def f():
    print a

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

import module1
a=3
module1.f()

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

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

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

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

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

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 *

И затем, как только я попытаюсь вызвать любую из функций утилит, он вызывает вышеупомянутую ошибку "global name not defined".

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

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

4b9b3361

Ответ 1

Глобалы в 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, инициализированную любым shared_stuff.a, упомянутым во время импорта, и эта новая переменная a не будет зависеть от назначений shared_stuff.a.


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

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

Ответ 2

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

main.py:

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

mymodule.py:

import os
print os.environ['MYVAL']

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

Ответ 3

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

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

Ответ 4

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

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

#sharedstuff.py

globaltimes_randomnode=[]
globalist_randomnode=[]

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

import sharedstuff as shared

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

from globals import *

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

Просто скажи

Ответ 5

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

module1:

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()

Ответ 6

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

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

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

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

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

module.addglobals(глобалы())

Ответ 7

Поскольку я не видел этого в ответах выше, я решил добавить свой простой обходной путь, который заключается в добавлении аргумента global_dict к функции, требующей глобальных переменных вызывающего модуля, и затем передачи dict в функцию при вызове; например:

# external_module
def imported_function(global_dict=None):
    print(global_dict["a"])


# calling_module
a = 12
from external_module import imported_function
imported_function(global_dict=globals())

>>> 12

Ответ 8

ООП способ сделать это состоит в том, чтобы сделать ваш модуль классом вместо набора несвязанных методов. Затем вы можете использовать __init__ или метод setter для установки переменных из вызывающей стороны для использования в методах модуля.