Використовуєте глобальні змінні між файлами?


208

Я трохи розгублений, як працюють глобальні змінні. У мене великий проект, який містить близько 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 або маринування, які Я не хочу цього робити.


Власне, ваш другий підхід для мене працює чудово. main.py правильно друкує "ей". Чи можете ви бути більш конкретними щодо того, що ви мені, "це не спрацювало"?
родіон

@rodion: імпорт циклів - код у підфілі намагається імпортувати globfile, який у itś body імпортує назад
jsbueno

1
NameError: name 'myList' is not definedвід main.pyлініїprint(globfile.myList[0])

Відповіді:


319

Проблема в тому , ви визначили 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

Таким чином ви досягаєте своєї мети, уникаючи глобальних змінних не один раз.


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

19
+1 Кірк: Я згоден. Однак мій підхід запобігає випадку, коли інші модулі змінюють globals.myList перед запуском основної програми.
Хай Ву

2
Ви повинні назвати це чимось, крім глобальних, що є вбудованою назвою. PyLint дає попередження: "Перевизначення вбудованих" глобалів "(переосмислений-вбудований)"
twasbrillig

Дякую. Будь-яка ідея, як видалити помилки "Не визначена зміна від імпорту", які з'являються в Eclipse PyDev, використовуючи цю файлову структуру (тобто імпорт глобальних змінних з settings.py)? Мені довелося відключити помилку в PyDev , що не ідеально.
Franck Dernoncourt

@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
Найпростіше рішення! Дякую
користувач1297406

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
га На перший погляд це виглядає саме так, чи не так? Що відбувається в def речі (), це те, що імпорт не запускається, коли файл завантажується. Він працює лише тоді, коли викликається функція stuff (). Отже, починаючи з main, ми імпортуємо subfile, а потім викликаємо subfile.stuff (), який потім імпортує main ... no цикл, просто імпортуємо один раз у 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

Відповідь Хай Ву чудово працює, лише один коментар:

Якщо ви використовуєте глобальний в іншому модулі і хочете динамічно встановити глобальний, зверніть увагу на імпорт інших модулів після встановлення глобальних змінних, наприклад:

# 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 - attr глобального файлу, а не підфайл. Це буде працювати, як ви хочете.

Майк

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.