Sử dụng biến toàn cục giữa các tập tin?


207

Tôi hơi bối rối về cách các biến toàn cầu hoạt động. Tôi có một dự án lớn, với khoảng 50 tệp và tôi cần xác định các biến toàn cục cho tất cả các tệp đó.

Những gì tôi đã làm là xác định chúng trong main.pytệp dự án của tôi , như sau:

# ../myproject/main.py

# Define global myList
global myList
myList = []

# Imports
import subfile

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

Tôi đang cố gắng để sử dụng myListtrong subfile.py, như sau

# ../myproject/subfile.py

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

Một cách khác tôi đã thử, nhưng cũng không hiệu quả

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

Và bên trong subfile.pytôi đã có điều này:

# ../myproject/subfile.py

# Import globfile
import globfile

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

Nhưng một lần nữa, nó đã không hoạt động. Làm thế nào tôi nên thực hiện điều này? Tôi hiểu rằng nó không thể hoạt động như vậy, khi hai tệp không thực sự biết nhau (thư mục con cũng không biết chính), nhưng tôi không thể nghĩ ra cách thực hiện, mà không sử dụng io viết hoặc ngâm, Tôi không muốn làm.


Trên thực tế, cách tiếp cận thứ hai của bạn hoạt động tốt cho tôi. main.txt in chính xác "hey". Bạn có thể cụ thể hơn về những gì bạn với tôi bằng "nó không hoạt động"?
Rodion

@rodion: nhập chu kỳ - mã trong tập tin con cố gắng nhập globalfile, trong đó phần thân nhập lại chính nó
jsbueno

1
NameError: name 'myList' is not definedtừ main.pydòngprint(globfile.myList[0])

Câu trả lời:


318

Vấn đề là bạn xác định myListtừ main.py, nhưng subfile.pycần phải sử dụng nó. Đây là một cách rõ ràng để giải quyết vấn đề này: di chuyển tất cả các quả địa cầu vào một tệp, tôi gọi tệp này settings.py. Tập tin này chịu trách nhiệm xác định toàn cầu và khởi tạo chúng:

# settings.py

def init():
    global myList
    myList = []

Tiếp theo, bạn subfilecó thể nhập toàn cầu:

# subfile.py

import settings

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

Lưu ý rằng subfilekhông gọi init()- nhiệm vụ đó thuộc về 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

Bằng cách này, bạn đạt được mục tiêu của mình trong khi tránh khởi tạo các biến toàn cục nhiều lần.


40
Tôi thích cách tiếp cận chung, nhưng không phải toàn bộ init(). Các mô-đun chỉ được đánh giá lần đầu tiên chúng được nhập, do đó, hoàn toàn ổn khi khởi tạo các biến đó trong phần thân của mô-đun.
Kirk Strauser

19
+1 Kirk: Tôi đồng ý. Tuy nhiên, cách tiếp cận của tôi ngăn chặn trường hợp các mô-đun khác sửa đổi globalals.myList trước khi chương trình chính bắt đầu.
Hải Vũ

2
Bạn nên gọi nó là một cái gì đó khác với toàn cầu, đó là một tên dựng sẵn. PyLint đưa ra cảnh báo: "Xác định lại 'toàn cầu' tích hợp (xác định lại được xây dựng)"
twasbrillig

Cảm ơn. Bất kỳ ý tưởng nào làm thế nào để loại bỏ biến không xác định của người dùng trong quá trình nhập lỗi lỗi xuất hiện trong Eclipse PyDev bằng cách sử dụng cấu trúc tệp này (tức là nhập các biến toàn cục từ settings.py)? Tôi đã phải vô hiệu hóa lỗi trong PyDev , điều này không lý tưởng.
Franck Dernoncourt

@FranckDernoncourt Tôi xin lỗi, tôi không sử dụng Eclipse vì vậy tôi thậm chí còn không biết gì hơn bạn.
Hải Vũ

92

Xem tài liệu của Python về việc chia sẻ các biến toàn cục trên các mô-đun :

Cách chính tắc để chia sẻ thông tin giữa các mô-đun trong một chương trình là tạo một mô-đun đặc biệt (thường được gọi là config hoặc cfg).

cấu hình:

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

Nhập mô-đun cấu hình trong tất cả các mô-đun ứng dụng của bạn; mô-đun sau đó trở nên có sẵn như là một tên toàn cầu.

chính:

import config
print (config.x)

hoặc là

from config import x
print (x)

Nói chung, không sử dụng từ nhập tên modul * . Làm như vậy sẽ làm xáo trộn không gian tên của nhà nhập khẩu và khiến cho việc phát hiện các tên không xác định trở nên khó khăn hơn nhiều.


1
Phao cứu sinh - chỉ cho liên kết đó!
toonarmycaptain

4
Đây có vẻ như là một cách tiếp cận sạch hơn câu trả lời được chấp nhận.
JoeyC

2
Lưu ý rằng bạn không thể thiết lập xbằng cách sử dụng from config import x, chỉ sử dụngimport config
Yariv

1
Giải pháp đơn giản nhất! Cảm ơn
user1297406

22

Bạn có thể nghĩ các biến toàn cục của Python là các biến "mô-đun" - và như vậy chúng hữu ích hơn nhiều so với các "biến toàn cục" truyền thống từ C.

Một biến toàn cục thực sự được định nghĩa trong một mô-đun __dict__và có thể được truy cập từ bên ngoài mô-đun đó như một thuộc tính mô-đun.

Vì vậy, trong ví dụ của bạn:

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

Và:

# ../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
wow, thông thường người ta sẽ mong đợi hai tập tin nhập vào nhau để vào một vòng lặp vô hạn.
Nikhil VJ

2
thoạt nhìn có vẻ như vậy phải không? Điều xảy ra trong def Stuff () là quá trình nhập không chạy khi tải tệp..tôi chỉ chạy khi hàm Stuff () được gọi. Vì vậy, bắt đầu với main chúng ta nhập subfile và sau đó gọi subfile. ware () mà sau đó nhập main ... không có vòng lặp, chỉ nhập một lần trong main. Xem ghi chú trong ví dụ subfile.py về chu kỳ nhập.
John

11

Sử dụng from your_file import *nên khắc phục vấn đề của bạn. Nó định nghĩa mọi thứ để nó có sẵn trên toàn cầu (ngoại trừ các biến cục bộ trong quá trình nhập khẩu).

ví dụ:

##test.py:

from pytest import *

print hello_world

và:

##pytest.py

hello_world="hello world!"

4
Ngoại trừ nếu bạn gán cho một biến như vậy
jsbueno

5
Cá nhân tôi tránh sử dụng bằng import *mọi giá để các tài liệu tham khảo rõ ràng (và không gây nhầm lẫn), Bên cạnh đó, khi nào bạn thực sự sử dụng tất cả các *tham chiếu "" trong bất kỳ mô-đun nào?
ThorSummoner

19
KHÔNG nhập khẩu *. Các biến toàn cầu của bạn sẽ không còn được đồng bộ hóa. Mỗi mô-đun nhận được bản sao riêng của mình. Thay đổi biến trong một tệp sẽ không phản ánh trong một tệp khác. Nó cũng được cảnh báo chống lại trong docs.python.org/2/faq/ Khăn
Isa Hassen

8

Câu trả lời của Hải Vũ rất tuyệt, chỉ một bình luận:

Trong trường hợp bạn đang sử dụng toàn cầu trong mô-đun khác và bạn muốn thiết lập toàn cầu một cách linh hoạt, hãy chú ý nhập các mô-đun khác sau khi bạn đặt các biến toàn cục, ví dụ:

# 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

Nỗ lực thứ 2 của bạn sẽ hoạt động hoàn hảo và thực sự là một cách thực sự tốt để xử lý các tên biến mà bạn muốn có sẵn trên toàn cầu. Nhưng bạn có một lỗi tên trong dòng cuối cùng. Đây là cách nó phải được:

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

Xem dòng cuối cùng? myList là một attr của globalfile, không phải là subfile. Điều này sẽ làm việc như bạn muốn.

Mike

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.