Menggunakan variabel global antar file?

209

Saya agak bingung tentang bagaimana variabel global bekerja. Saya punya proyek besar, dengan sekitar 50 file, dan saya perlu mendefinisikan variabel global untuk semua file itu.

Apa yang saya lakukan adalah mendefinisikannya dalam main.pyfile proyek saya , sebagai berikut:

# ../myproject/main.py

# Define global myList
global myList
myList = []

# Imports
import subfile

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

Saya mencoba untuk menggunakan myListdi subfile.py, sebagai berikut

# ../myproject/subfile.py

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

Cara lain saya mencoba, tetapi tidak berhasil juga

# ../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])

Dan di dalam subfile.pysaya punya ini:

# ../myproject/subfile.py

# Import globfile
import globfile

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

Tetapi sekali lagi, itu tidak berhasil. Bagaimana saya harus menerapkan ini? Saya mengerti bahwa itu tidak bisa berfungsi seperti itu, ketika dua file tidak benar-benar mengenal satu sama lain (well subfile tidak tahu utama), tapi saya tidak bisa memikirkan bagaimana melakukannya, tanpa menggunakan io tulisan atau acar, yang Saya tidak ingin melakukannya.

martineau
sumber
Sebenarnya, pendekatan kedua Anda bekerja dengan baik untuk saya. main.py dengan benar mencetak "hei". Bisakah Anda lebih spesifik pada apa yang Anda saya dengan "tidak berhasil"?
Rodion
@rodion: mengimpor siklus - kode dalam subfile mencoba mengimpor globfile, yang di dalamnya ś tubuh mengimpor sendiri kembali
jsbueno
1
NameError: name 'myList' is not defineddari main.pylineprint(globfile.myList[0])

Jawaban:

321

Masalahnya Anda tetapkan myListdari mana main.py, tetapi subfile.pyperlu menggunakannya. Ini adalah cara bersih untuk menyelesaikan masalah ini: pindahkan semua global ke sebuah file, saya sebut file ini settings.py. File ini bertanggung jawab untuk mendefinisikan global dan menginisialisasi mereka:

# settings.py

def init():
    global myList
    myList = []

Selanjutnya, Anda subfiledapat mengimpor global:

# subfile.py

import settings

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

Catatan yang subfiletidak memanggil init()- tugas itu milik 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

Dengan cara ini, Anda mencapai tujuan Anda sambil menghindari menginisialisasi variabel global lebih dari sekali.

Hai Vu
sumber
41
Saya suka pendekatan umum, tetapi tidak semuanya init(). Modul hanya dievaluasi saat pertama kali diimpor, jadi sangat baik untuk menginisialisasi variabel-variabel tersebut di dalam tubuh modul.
Kirk Strauser
19
+1 Kirk: Saya setuju. Namun, pendekatan saya mencegah kasus di mana modul lain memodifikasi globals.myList sebelum program utama dimulai.
Hai Vu
2
Anda harus menyebutnya sesuatu selain global, yang merupakan nama bawaan. PyLint memberi peringatan: "Mendefinisikan ulang built-in 'global' (redefined-builtin)"
twasbrillig
Terima kasih. Adakah yang tahu cara menghapus kesalahan "Undefined variable from import" yang muncul di Eclipse PyDev dengan menggunakan struktur file ini (mis. Mengimpor variabel global dari settings.py)? Saya harus menonaktifkan kesalahan di PyDev , yang tidak ideal.
Franck Dernoncourt
@ FranckDernoncourt Maaf, saya tidak menggunakan Eclipse jadi saya lebih tidak mengerti daripada Anda.
Hai Vu
94

Lihat dokumen Python tentang berbagi variabel global di seluruh modul :

Cara kanonik untuk berbagi informasi lintas modul dalam satu program adalah membuat modul khusus (sering disebut config atau cfg).

config.py:

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

Impor modul konfigurasi di semua modul aplikasi Anda; modul kemudian tersedia sebagai nama global.

main.py:

import config
print (config.x)

atau

from config import x
print (x)

Secara umum, jangan gunakan dari impor modulename * . Melakukan hal itu mengacaukan namespace importir, dan mempersulit linter untuk mendeteksi nama yang tidak terdefinisi.

Ogaga Uzoh
sumber
1
Penyelamat - hanya untuk tautan itu!
toonarmycaptain
4
Ini sepertinya pendekatan yang lebih bersih daripada jawaban yang diterima.
JoeyC
2
Perhatikan bahwa Anda tidak dapat mengatur xmenggunakan from config import x, hanya menggunakanimport config
Yariv
1
Solusi paling sederhana! Terima kasih
user1297406
22

Anda dapat menganggap variabel global Python sebagai variabel "modul" - dan karenanya mereka jauh lebih berguna daripada "variabel global" tradisional dari C.

Variabel global sebenarnya didefinisikan dalam modul __dict__ dan dapat diakses dari luar modul sebagai atribut modul.

Jadi, dalam contoh Anda:

# ../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])

Dan:

# ../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
sumber
1
wow, biasanya satu akan berharap dua file saling mengimpor untuk masuk ke loop tak terbatas.
Nikhil VJ
2
ha Sepintas seperti itu, kan? Apa yang terjadi di def stuff () adalah bahwa impor tidak berjalan ketika file dimuat .. hanya berjalan ketika fungsi stuff () dipanggil. Jadi dimulai dengan main kita mengimpor subfile dan kemudian memanggil subfile.stuff () yang kemudian mengimpor utama ... tanpa loop, cukup impor sekali di utama. Lihat catatan pada contoh subfile.py tentang siklus impor.
John
11

Penggunaan from your_file import *harus memperbaiki masalah Anda. Ini mendefinisikan semuanya sehingga tersedia secara global (dengan pengecualian variabel lokal dalam impor tentu saja).

sebagai contoh:

##test.py:

from pytest import *

print hello_world

dan:

##pytest.py

hello_world="hello world!"
Ninja IT
sumber
4
Kecuali jika Anda menetapkan satu variabel seperti itu
jsbueno
5
Saya pribadi menghindari penggunaan import *dengan cara apa pun sehingga referensi bersifat eksplisit (dan tidak membingungkan), Selain itu, kapan Anda pernah menggunakan semua *referensi " " dalam modul apa saja?
ThorSummoner
19
JANGAN LAKUKAN impor *. Variabel global Anda tidak akan lagi tetap sinkron. Setiap modul menerima salinannya sendiri. Mengubah variabel dalam satu file tidak akan mencerminkan yang lain. Hal ini juga diperingatkan terhadap di docs.python.org/2/faq/…
Isa Hassen
8

Jawaban Hai Vu bekerja dengan baik, hanya satu komentar:

Jika Anda menggunakan global dalam modul lain dan Anda ingin mengatur global secara dinamis, perhatikan untuk mengimpor modul lain setelah Anda mengatur variabel global, misalnya:

# 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
sumber
4

Upaya ke-2 Anda akan bekerja dengan sempurna, dan sebenarnya cara yang sangat baik untuk menangani nama variabel yang ingin Anda miliki secara global. Tetapi Anda memiliki kesalahan nama di baris terakhir. Beginilah seharusnya:

# ../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])

Lihat baris terakhir? myList adalah attr dari globfile, bukan subfile. Ini akan berfungsi seperti yang Anda inginkan.

Mike

MikeHunter
sumber