Использование глобальных переменных между файлами?


209

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

Я определил их в main.pyфайле моих проектов следующим образом:

# ../myproject/main.py

# Define global myList
global myList
myList = []

# Imports
import subfile

# Do something
subfile.stuff()
print(myList[0])

Я пытаюсь использовать myListв subfile.py, следующим образом

# ../myproject/subfile.py

# Save "hey" into myList
def stuff():
    globals()["myList"].append("hey")

Другой способ, которым я пытался, но тоже не работал

# ../myproject/main.py

# Import globfile    
import globfile

# Save myList into globfile
globfile.myList = []

# Import subfile
import subfile

# Do something
subfile.stuff()
print(globfile.myList[0])

И внутри у subfile.pyменя было это:

# ../myproject/subfile.py

# Import globfile
import globfile

# Save "hey" into myList
def stuff():
    globfile.myList.append("hey")

Но опять же, это не сработало. Как мне это реализовать? Я понимаю, что это не может работать так, когда два файла на самом деле не знают друг друга (хорошо, подфайл не знает основной), но я не могу придумать, как это сделать, не используя io write или pickle, что Я не хочу делать


На самом деле, ваш второй подход прекрасно работает для меня. main.py правильно печатает "эй". Можете ли вы быть более конкретным на то, что вы мне "не работает"?
Родион

@rodion: импорт циклов - код в подфайле пытается импортировать глобальный файл, который в нем… тело импортирует обратно
jsbueno

1
NameError: name 'myList' is not definedсо main.pyстрокиprint(globfile.myList[0])

Ответы:


321

Проблема в том , вы определили myListот main.py, но subfile.pyнужно использовать. Вот простой способ решить эту проблему: переместить все глобальные переменные в файл, я называю этот файл settings.py. Этот файл отвечает за определение глобалов и их инициализацию:

# settings.py

def init():
    global myList
    myList = []

Далее вы subfileможете импортировать глобалы:

# subfile.py

import settings

def stuff():
    settings.myList.append('hey')

Обратите внимание, что subfileне вызывает init()- эта задача принадлежит main.py:

# main.py

import settings
import subfile

settings.init()          # Call only once
subfile.stuff()         # Do stuff with global var
print settings.myList[0] # Check the result

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


41
Мне нравится общий подход, но не весь init()материал. Модули оцениваются только в первый раз, когда они импортируются, поэтому вполне нормально инициализировать эти переменные в теле модуля.
Кирк Штраузер

19
+1 Кирк: я согласен. Однако мой подход предотвращает случай, когда другие модули изменяют globals.myList до запуска основной программы.
Хай Ву

2
Вы должны называть это чем-то другим, кроме глобалов, что является встроенным именем. PyLint выдает предупреждение: «Переопределение встроенных« глобалов »(redefined-builtin)»
twasbrillig

Спасибо. Любая идея, как удалить ошибки «Неопределенная переменная из импорта», которые появляются в Eclipse PyDev, используя эту файловую структуру (то есть, импортируя глобальные переменные из settings.py)? Мне пришлось отключить ошибку в PyDev , что не идеально.
Франк Дернонкур

@FranckDernoncourt Извините, я не использую Eclipse, поэтому я еще более невежествен, чем вы.
Хай Ву

94

См. Документ Python о совместном использовании глобальных переменных между модулями :

Канонический способ обмена информацией между модулями в рамках одной программы - создать специальный модуль (часто называемый config или cfg).

config.py:

x = 0   # Default value of the 'x' configuration setting

Импортируйте модуль конфигурации во все модули вашего приложения; модуль становится доступным как глобальное имя.

main.py:

import config
print (config.x)

или

from config import x
print (x)

В общем, не используют из имя_модуля импорта * . Это приводит к загромождению пространства имен импортера и затрудняет для линтеров обнаружение неопределенных имен.


1
Спасатель - только по этой ссылке!
toonarmycaptain

4
Это похоже на более чистый подход, чем принятый ответ.
JoeyC

2
Обратите внимание , что вы не можете установить с xпомощью from config import x, используя толькоimport config
Ярив

1
Самое простое решение! Спасибо
user1297406

22

Вы можете думать о глобальных переменных Python как о «модульных» переменных - и поэтому они гораздо более полезны, чем традиционные «глобальные переменные» из C.

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

Итак, в вашем примере:

# ../myproject/main.py

# Define global myList
# global myList  - there is no "global" declaration at module level. Just inside
# function and methods
myList = []

# Imports
import subfile

# Do something
subfile.stuff()
print(myList[0])

И:

# ../myproject/subfile.py

# Save "hey" into myList
def stuff():
     # You have to make the module main available for the 
     # code here.
     # Placing the import inside the function body will
     # usually avoid import cycles - 
     # unless you happen to call this function from 
     # either main or subfile's body (i.e. not from inside a function or method)
     import main
     main.mylist.append("hey")

1
вау, обычно можно ожидать, что два импортирующих друг друга файла попадут в бесконечный цикл.
Nikhil VJ

2
ha На первый взгляд все выглядит так, не так ли? В def вещи () происходит то, что импорт не запускается при загрузке файла .. он запускается только при вызове функции stuff (). Итак, начиная с main, мы импортируем subfile, а затем вызываем subfile.stuff (), который затем импортирует main ... no loop, просто импортируем один раз в main. См. Примечание в примере subfile.py о циклах импорта.
Джон

11

Использование from your_file import *должно исправить ваши проблемы. Он определяет все так, чтобы он был глобально доступен (за исключением локальных переменных в импорте, конечно).

например:

##test.py:

from pytest import *

print hello_world

и:

##pytest.py

hello_world="hello world!"

4
За исключением случаев, когда вы присваиваете одну такую ​​переменную
jsbueno

5
Я лично избегаю использования import *любой ценой, чтобы ссылки были явными (и не сбивающими с толку). Кроме того, когда вы когда-нибудь использовали все " *" ссылки в каком-либо модуле?
ThorSummoner

19
НЕ ДЕЛАЙТЕ импорт *. Ваши глобальные переменные больше не будут синхронизироваться. Каждый модуль получает свою собственную копию. Изменение переменной в одном файле не отразится на другом. Об этом также предупреждают в docs.python.org/2/faq/…
Иса Хассен

8

Hai Vu прекрасно работает, всего один комментарий:

Если вы используете глобальный модуль в другом модуле и хотите установить глобальный динамически, обратите внимание на импорт других модулей после установки глобальных переменных, например:

# settings.py
def init(arg):
    global myList
    myList = []
    mylist.append(arg)


# subfile.py
import settings

def print():
    settings.myList[0]


# main.py
import settings
settings.init("1st")     # global init before used in other imported modules
                         # Or else they will be undefined

import subfile    
subfile.print()          # global usage

4

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

# ../myproject/main.py

# Import globfile    
import globfile

# Save myList into globfile
globfile.myList = []

# Import subfile
import subfile

# Do something
subfile.stuff()
print(globfile.myList[0])

Видите последнюю строчку? myList является атрибутом globfile, а не subfile. Это будет работать, как вы хотите.

Майк

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.