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

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")
jsbueno
источник
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!"
IT ниндзя
источник
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
lastboy
источник
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. Это будет работать, как вы хотите.

Майк

MikeHunter
источник