ฉันได้ตอบคำถามเกี่ยวกับการนำเข้าแบบสัมบูรณ์ใน Python ซึ่งฉันคิดว่าฉันเข้าใจโดยอ้างอิงจากการอ่านPython 2.5 changelogและPEP ที่มาพร้อมกัน อย่างไรก็ตามเมื่อติดตั้ง Python 2.5 และพยายามสร้างตัวอย่างของการใช้อย่างถูกต้องfrom __future__ import absolute_import
ฉันรู้ว่าสิ่งต่าง ๆ ไม่ชัดเจนนัก
ตรงจากรายการเชื่อมโยงข้างต้นคำสั่งนี้สรุปความเข้าใจของฉันเกี่ยวกับการเปลี่ยนแปลงการนำเข้าแบบสัมบูรณ์:
สมมติว่าคุณมีไดเรกทอรีแพ็คเกจเช่นนี้:
pkg/ pkg/__init__.py pkg/main.py pkg/string.py
สิ่งนี้จะกำหนดแพ็คเกจ
pkg
ที่มีชื่อpkg.main
และpkg.string
submodulesพิจารณารหัสในโมดูล main.py จะเกิดอะไรขึ้นถ้ามันประมวลผลคำสั่ง
import string
? ใน Python 2.4 และรุ่นก่อนหน้ามันจะดูในไดเรกทอรีของแพ็คเกจเพื่อดำเนินการนำเข้าแบบสัมพัทธ์ค้นหา pkg / string.py นำเข้าเนื้อหาของไฟล์นั้นเป็นpkg.string
โมดูลและโมดูลนั้นถูกผูกไว้กับชื่อ"string"
ในpkg.main
เนมสเปซของโมดูล
ดังนั้นฉันจึงสร้างโครงสร้างไดเรกทอรีที่แน่นอนนี้:
$ ls -R
.:
pkg/
./pkg:
__init__.py main.py string.py
__init__.py
และstring.py
ว่างเปล่า main.py
มีรหัสต่อไปนี้:
import string
print string.ascii_uppercase
ตามที่คาดไว้การรันด้วย Python 2.5 จะล้มเหลวด้วยAttributeError
:
$ python2.5 pkg/main.py
Traceback (most recent call last):
File "pkg/main.py", line 2, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
อย่างไรก็ตามต่อไปในการเปลี่ยนแปลง 2.5 เราพบสิ่งนี้ (เน้นการเพิ่ม):
ใน Python 2.5 คุณสามารถสลับ
import
การทำงานเป็นการนำเข้าแบบสัมบูรณ์โดยใช้from __future__ import absolute_import
คำสั่ง พฤติกรรมการนำเข้าแบบสัมบูรณ์นี้จะกลายเป็นค่าเริ่มต้นในเวอร์ชันในอนาคต (อาจเป็น Python 2.7) เมื่อการนำเข้าแบบสัมบูรณ์เป็นค่าเริ่มต้นimport string
จะค้นหาเวอร์ชันของไลบรารีมาตรฐานเสมอ
ฉันสร้างขึ้นpkg/main2.py
เหมือนกันmain.py
แต่มีคำสั่งการนำเข้าเพิ่มเติมในอนาคต ตอนนี้ดูเหมือนว่านี้:
from __future__ import absolute_import
import string
print string.ascii_uppercase
รันด้วย Python 2.5 อย่างไรก็ตาม ... ล้มเหลวด้วยAttributeError
:
$ python2.5 pkg/main2.py
Traceback (most recent call last):
File "pkg/main2.py", line 3, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
นี้สวยอย่างเด็ดขาดขัดแย้งกับคำสั่งที่import string
จะเสมอหารุ่น STD-lib กับการนำเข้าการเปิดใช้งานแน่นอน แม้จะมีคำเตือนว่าการนำเข้าสัมบูรณ์นั้นถูกกำหนดให้เป็นพฤติกรรม "เริ่มต้นใหม่" แต่ฉันก็พบปัญหาเดียวกันนี้โดยใช้ Python 2.7 ทั้งที่มีหรือไม่มี__future__
คำสั่ง:
$ python2.7 pkg/main.py
Traceback (most recent call last):
File "pkg/main.py", line 2, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
$ python2.7 pkg/main2.py
Traceback (most recent call last):
File "pkg/main2.py", line 3, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
เช่นเดียวกับ Python 3.5 โดยมีหรือไม่มี (สมมติว่าprint
คำสั่งเปลี่ยนไปในทั้งสองไฟล์):
$ python3.5 pkg/main.py
Traceback (most recent call last):
File "pkg/main.py", line 2, in <module>
print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'
$ python3.5 pkg/main2.py
Traceback (most recent call last):
File "pkg/main2.py", line 3, in <module>
print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'
ฉันได้ทดสอบรูปแบบอื่น ๆ ของสิ่งนี้แล้ว แทนที่จะเป็นstring.py
ฉันได้สร้างโมดูลว่าง - ไดเรกทอรีstring
ที่มีเพียงว่าง__init__.py
- และแทนที่จะออกจากการนำเข้าmain.py
ฉันมีcd
'ไปที่pkg
และเรียกใช้การนำเข้าโดยตรงจาก REPL การเปลี่ยนแปลงเหล่านี้ (หรือการรวมกันของทั้งสองอย่าง) ไม่ได้เปลี่ยนผลลัพธ์ข้างต้น ฉันไม่สามารถกระทบยอดกับสิ่งที่ฉันได้อ่านเกี่ยวกับ__future__
การนำเข้าคำสั่งและแบบสัมบูรณ์
ดูเหมือนว่าสำหรับฉันแล้วสิ่งนี้สามารถอธิบายได้อย่างง่ายดายโดยสิ่งต่อไปนี้ (นี่คือจากเอกสาร Python 2 แต่ข้อความนี้ยังคงไม่เปลี่ยนแปลงในเอกสารเดียวกันสำหรับ Python 3):
sys.path
( ... )
ตามที่เริ่มต้นเมื่อเริ่มต้นโปรแกรมรายการแรกของรายการนี้
path[0]
เป็นไดเรกทอรีที่มีสคริปต์ที่ใช้ในการเรียก Python interpreter หากไดเรกทอรีของสคริปต์ไม่พร้อมใช้งาน (เช่นถ้าล่ามถูกเรียกใช้แบบโต้ตอบหรือถ้าสคริปต์ถูกอ่านจากอินพุตมาตรฐาน)path[0]
เป็นสตริงว่างซึ่งนำ Python ไปยังโมดูลการค้นหาในไดเรกทอรีปัจจุบันก่อน
แล้วฉันจะพลาดอะไรไป? เหตุใดข้อความดังกล่าวจึงไม่__future__
ปรากฏตามที่กล่าวและความละเอียดของความขัดแย้งระหว่างเอกสารทั้งสองส่วนนี้รวมถึงพฤติกรรมที่อธิบายและที่เกิดขึ้นจริงคืออะไร