ฉันสามารถใช้ __init__.py เพื่อกำหนดตัวแปรส่วนกลางได้หรือไม่


131

ฉันต้องการกำหนดค่าคงที่ที่ควรมีอยู่ในโมดูลย่อยทั้งหมดของแพ็กเกจ ฉันคิดว่าตำแหน่งที่ดีที่สุดจะอยู่ใน__init__.pyไฟล์ของแพ็คเกจรูท แต่ฉันไม่รู้ว่าต้องทำอย่างไร สมมติว่าฉันมีแพ็กเกจย่อยสองสามแพ็กเกจและแต่ละแพ็กเกจมีหลายโมดูล ฉันจะเข้าถึงตัวแปรนั้นจากโมดูลเหล่านี้ได้อย่างไร

แน่นอนว่าหากสิ่งนี้ผิดโดยสิ้นเชิงและมีทางเลือกอื่นที่ดีกว่าฉันก็อยากจะรู้

คำตอบ:


196

คุณควรจะใส่เข้าไป__init__.pyได้ นี้ทำตลอดเวลา

mypackage/__init__.py:

MY_CONSTANT = 42

mypackage/mymodule.py:

from mypackage import MY_CONSTANT
print "my constant is", MY_CONSTANT

จากนั้นนำเข้า mymodule:

>>> from mypackage import mymodule
my constant is 42

ถึงกระนั้นหากคุณมีค่าคงที่ก็เป็นเรื่องที่สมเหตุสมผล (แนวทางปฏิบัติที่ดีที่สุดอาจ) ที่จะใส่ไว้ในโมดูลแยกต่างหาก (constants.py, config.py, ... ) จากนั้นหากคุณต้องการให้อยู่ในเนมสเปซแพ็กเกจให้นำเข้า พวกเขา

mypackage/__init__.py:

from mypackage.constants import *

ถึงกระนั้นก็ยังไม่รวมค่าคงที่ในเนมสเปซของโมดูลแพ็กเกจโดยอัตโนมัติ แต่ละโมดูลในแพคเกจจะยังคงต้องคงที่การนำเข้าอย่างชัดเจนทั้งจากหรือจากmypackagemypackage.constants


19
นี่ควรเป็นคำตอบที่ได้รับการยอมรับ หากคุณกำลังทำงานกับ Python 2.5 หรือสูงกว่าคุณสามารถใช้การนำเข้าสัมพัทธ์อย่างชัดเจนได้เช่นกันตามที่อธิบายไว้ที่นี่ : from . import MY_CONSTANT
ThatAintWorking

วิธีที่สองใช้เฉพาะกับค่าคงที่ไม่ใช่หรือ from mypackage.constants import *จะวางสำเนาMY_CONSTANTในทุกโมดูลย่อยแทนที่จะอ้างอิงถึงตัวแปรเดียวกัน
hardmooth

@hardmooth: ไม่แน่นอน ค่าจะถูกคัดลอกโดยการอ้างอิงดังนั้นหากคุณจะกลายพันธุ์MY_CONSTANTในโมดูลใด ๆ ค่านั้นจะกลายพันธุ์ทุกที่ หากคุณต้องกำหนดซ้ำMY_CONSTANTในโมดูลใด ๆ จะมีผลกับโมดูลนั้นเท่านั้น mypackage.constants.MY_CONSTANTหากเป็นความตั้งใจของคุณคุณต้องอ้างอิงตามลักษณะเฉพาะคือ
Jason R.Combs

7
หนึ่งจับกับตัวอย่างคือถ้าคุณนำเข้าmymodule.pyใน__init__.pyก่อนMY_CONSTANT = 42ที่จะล้มเหลวเพราะเมื่อนำเข้าmymodule.py MY_CONSTANTยังไม่ได้รับการกำหนดเลย ดังนั้นต้องย้ายMY_CONSTANT = 42ด้านบนimport mymodule
markmnl

ตัวแปรเป็นอย่างไร? มันถามเกี่ยวกับตัวแปรไม่ใช่ค่าคงที่ python ปฏิบัติต่อตัวแปรภายในแพ็คเกจอย่างไร เกิดอะไรขึ้นถ้าตัวแปรภายในแพ็คเกจถูกเปลี่ยน?
TomSawyer

31

คุณไม่สามารถทำเช่นนั้นได้ คุณจะต้องนำเข้าค่าคงที่ของคุณอย่างชัดเจนไปยังเนมสเปซของแต่ละโมดูล วิธีที่ดีที่สุดในการบรรลุเป้าหมายนี้คือกำหนดค่าคงที่ของคุณในโมดูล "config" และนำเข้าทุกที่ที่คุณต้องการ:

# mypackage/config.py
MY_CONST = 17

# mypackage/main.py
from mypackage.config import *

ใช่ไฟล์กำหนดค่าคือสิ่งที่ฉันต้องการ ฉันแค่คิดว่าinit. py จะเป็นสถานที่ที่ดี วิธีแก้ปัญหาของคุณดูเหมือนการปฏิบัติตามมาตรฐาน ใช่ไหม?
Andrei Vajna II

1
จุดดี. ฉันไม่ทราบว่าคำถามคือการวางค่าคงที่โดยอัตโนมัติในเนมสเปซของโมดูลแพ็คเกจทั้งหมด
Jason R.Combs

แต่ทุกครั้งที่สคริปต์นำเข้า config.py โค้ดภายในจะถูกเรียกใช้งาน คุณจะแนะนำอะไรหากต้องรันโค้ดภายใน config.py เพียงครั้งเดียว สมมติว่าฉันกำลังอ่านไฟล์ settings.json ภายใน config.py และฉันไม่ต้องการเปิด () ทุกครั้งที่นำเข้า config.py
Augiwan

@UGS นี่ไม่ใช่วิธีการทำงานของ Python ทุกโมดูลจะดำเนินการเพียงครั้งเดียว sys.modulesเมื่อมันถูกนำเข้าครั้งที่สองโมดูลแคชแล้วใน
Ferdinand Beyer

@FerdinandBeyer อ๊ะ! ฉันลืมบอกไปว่าฉันกำลังนำเข้า config.py จากหลายสคริปต์ไม่ใช่สคริปต์เดียวกัน สมมติว่า a.py กำลังนำเข้า config.py & b.py และ b.py กำลังนำเข้า config.py ฉันสงสัยว่าเป็นไปได้หรือไม่ที่จะทำให้แน่ใจว่าโค้ดภายใน config.py ถูกเรียกใช้เพียงครั้งเดียว
Augiwan

2

คุณสามารถกำหนดตัวแปรส่วนกลางได้จากทุกที่ แต่เป็นความคิดที่แย่มาก นำเข้า__builtin__โมดูลและแก้ไขหรือเพิ่มแอตทริบิวต์ให้กับโมดูลนี้และทันใดนั้นคุณก็มีค่าคงที่หรือฟังก์ชันในตัวใหม่ ในความเป็นจริงเมื่อแอปพลิเคชันของฉันติดตั้ง gettext ฉันจะได้รับฟังก์ชัน _ () ในโมดูลทั้งหมดของฉันโดยไม่ต้องนำเข้าอะไรเลย ดังนั้นจึงเป็นไปได้ แต่แน่นอนสำหรับโครงการประเภทแอปพลิเคชันเท่านั้นไม่ใช่สำหรับแพ็คเกจหรือโมดูลที่ใช้ซ้ำได้

และฉันเดาว่าไม่มีใครแนะนำวิธีปฏิบัตินี้อยู่แล้ว เนมสเปซมีอะไรผิดปกติ แอพลิเคชันกล่าวว่ามีโมดูลรุ่นเพื่อให้ฉันมีตัวแปร "ทั่วโลก" ที่มีอยู่เช่นversion.VERSION, version.PACKAGE_NAMEฯลฯ


0

เพียงต้องการเพิ่มค่าคงที่สามารถใช้โดยใช้ไฟล์ config.ini และแยกวิเคราะห์ในสคริปต์โดยใช้ไลบรารี configparser วิธีนี้จะทำให้คุณมีค่าคงที่สำหรับหลาย ๆ สถานการณ์ ตัวอย่างเช่นหากคุณมีค่าคงที่พารามิเตอร์สำหรับคำขอ URL สองรายการที่แยกจากกันก็ให้ติดป้ายกำกับไว้ดังนี้:

mymodule/config.ini
[request0]
conn = 'admin@localhost'
pass = 'admin'
...

[request1]
conn = 'barney@localhost'
pass = 'dinosaur'
...

ฉันพบว่าเอกสารในเว็บไซต์ Python มีประโยชน์มาก ฉันไม่แน่ใจว่ามีความแตกต่างระหว่าง Python 2 และ 3 หรือไม่ดังนั้นนี่คือลิงก์ไปยังทั้งสอง:

สำหรับ Python 3: https://docs.python.org/3/library/configparser.html#module-configparser

สำหรับ Python 2: https://docs.python.org/2/library/configparser.html#module-configparser

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