ใช้ตัวแปรทั่วโลกระหว่างไฟล์?


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 เขียนหรือดองซึ่ง ฉันไม่ต้องการทำ


จริงๆแล้วแนวทางที่สองของคุณใช้ได้ดีสำหรับฉัน main.py พิมพ์ "เฮ้" อย่างถูกต้อง คุณจะเจาะจงมากขึ้นในสิ่งที่คุณฉันด้วย "มันไม่ทำงาน"?
rodion

@rodion: การนำเข้ารอบ - รหัสใน subfile พยายามที่จะนำเข้า globfile ซึ่งในนั้นร่างกายนำเข้าตัวเองกลับมา
jsbueno

1
NameError: name 'myList' is not definedจากmain.pyบรรทัดprint(globfile.myList[0])

คำตอบ:


320

ปัญหาคือคุณกำหนดmyListจากmain.pyแต่subfile.pyจำเป็นต้องใช้ นี่เป็นวิธีที่สะอาดเพื่อแก้ปัญหานี้: ย้าย globals ทั้งหมดไปยังไฟล์ฉันเรียกไฟล์settings.pyนี้ ไฟล์นี้มีหน้าที่กำหนด globals และเริ่มต้นพวกเขา:

# settings.py

def init():
    global myList
    myList = []

ถัดไปของคุณsubfileสามารถนำเข้า globals:

# 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()สิ่ง โมดูลจะได้รับการประเมินในครั้งแรกที่มีการนำเข้าดังนั้นจึงเป็นเรื่องที่ดีที่จะเริ่มต้นตัวแปรเหล่านั้นในส่วนของโมดูล
Kirk Strauser

19
+1 Kirk: ฉันเห็นด้วย อย่างไรก็ตามวิธีการของฉันป้องกันกรณีที่โมดูลอื่น ๆ แก้ไข globals.myList ก่อนที่โปรแกรมหลักจะเริ่ม
ไห่หวู

2
คุณควรเรียกมันว่าชื่ออื่นนอกเหนือจากกลมซึ่งเป็นชื่อในตัว PyLint ให้คำเตือน: "นิยามใหม่ของ 'globals' ในตัว (นิยามใหม่ - สร้างขึ้นภายใน)"
twasbrillig

ขอบคุณ มีแนวคิดใดที่จะลบข้อผิดพลาด“ ตัวแปรที่ไม่ได้กำหนดจากการนำเข้า” ที่ปรากฏใน Eclipse PyDev โดยใช้โครงสร้างไฟล์นี้ (เช่นการนำเข้าตัวแปรส่วนกลางจาก settings.py) ฉันต้องปิดการใช้งานข้อผิดพลาดใน PyDevซึ่งไม่เหมาะ
Franck Dernoncourt

@FranckDernoncourt ฉันขอโทษฉันไม่ได้ใช้ Eclipse ดังนั้นฉัน clueless ยิ่งกว่าคุณ
Hai Vu

94

ดูเอกสารของไพ ธ อนเกี่ยวกับการแบ่งปันตัวแปรทั่วโลกในโมดูล :

วิธีมาตรฐานของการแบ่งปันข้อมูลระหว่างโมดูลภายในโปรแกรมเดียวคือการสร้างโมดูลพิเศษ (มักเรียกว่า 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)

โดยทั่วไปไม่ได้ใช้จากการนำเข้า modulename * การทำเช่นนี้จะตัดเนมสเปซของผู้นำเข้าและทำให้มันยากขึ้นมากในการตรวจหาชื่อที่ไม่ได้กำหนด


1
ช่วยชีวิต - เพียงเพื่อลิงค์นั้น!
toonarmycaptain

4
ดูเหมือนว่าวิธีการที่สะอาดกว่าคำตอบที่ยอมรับ
JoeyC

2
โปรดทราบว่าคุณไม่สามารถตั้งค่าxโดยใช้from config import xเพียงใช้import config
Yariv

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
เมื่อมองอย่างแรกมันก็เป็นอย่างนั้นเหรอ? สิ่งที่เกิดขึ้นในไฟล์ 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/…
Isa Hassen

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 เป็น attr ของ globfile ไม่ใช่ subfile สิ่งนี้จะทำงานได้ตามที่คุณต้องการ

ไมค์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.