ทุกคนสามารถอธิบายการนำเข้าที่เกี่ยวข้องของงูใหญ่ได้หรือไม่


174

ฉันไม่สามารถใช้ชีวิตให้กับฉันได้ ฉันได้สร้างตัวอย่างง่ายๆที่ไม่ได้ทำงาน:

โครงสร้างไดเรกทอรีคือ:

/__init__.py
/start.py
/parent.py
/sub/__init__.py
/sub/relative.py

/start.py มีเพียง: import sub.relative

/sub/relative.py มีเพียง from .. import parent

ไฟล์อื่น ๆ ทั้งหมดว่างเปล่า

เมื่อดำเนินการต่อไปนี้บนบรรทัดคำสั่ง:

$ cd /
$ python start.py

ฉันเข้าใจ:

Traceback (most recent call last):
  File "start.py", line 1, in <module>
    import sub.relative
  File "/home/cvondrick/sandbox/sub/relative.py", line 1, in <module>
    from .. import parent
ValueError: Attempted relative import beyond toplevel package

ฉันใช้ Python 2.6 ทำไมเป็นกรณีนี้ ฉันจะทำให้ตัวอย่าง sandbox นี้ทำงานได้อย่างไร

คำตอบ:


140

คุณกำลังนำเข้าจากแพ็คเกจ "sub" start.pyไม่ได้อยู่ในแพ็คเกจแม้ว่าจะมี__init__.pyของขวัญก็ตาม

คุณจะต้องเริ่มโปรแกรมจากไดเรกทอรีเดียวparent.py:

./start.py

./pkg/__init__.py
./pkg/parent.py
./pkg/sub/__init__.py
./pkg/sub/relative.py

ด้วยstart.py:

import pkg.sub.relative

ตอนนี้ pkg เป็นแพ็คเกจระดับบนสุดและการนำเข้าที่เกี่ยวข้องของคุณควรใช้งานได้


import parentหากคุณต้องการที่จะยึดติดกับรูปแบบปัจจุบันของคุณคุณก็สามารถใช้ เนื่องจากคุณใช้start.pyเพื่อเรียกใช้ล่ามของคุณไดเรกทอรีที่start.pyอยู่ในเส้นทางของหลาม parent.pyอาศัยอยู่ที่นั่นเป็นโมดูลแยกต่างหาก

นอกจากนี้คุณยังสามารถลบระดับบนสุดได้อย่างปลอดภัย__init__.pyหากคุณไม่นำเข้าสิ่งใด ๆ ลงในสคริปต์ที่อยู่ด้านบนทรีไดเรกทอรี


2
คุณกำลังสับสนคำว่า 'โมดูล' และ 'แพ็คเกจ' 'start.py' หมายถึงโมดูล 'start', 'mod' และ 'mod.sub' เป็นแพ็กเกจ 'mod' เป็นแพ็คเกจระดับบนสุด
เฟอร์ดินานด์เบเยอร์

34
ขอบคุณ แต่สิ่งนี้ดูเหมือนจะโง่จริงๆ สำหรับภาษาที่สวยงามเช่นนี้ฉันไม่อยากจะเชื่อเลยว่านักออกแบบจะสร้างข้อ จำกัด ดังกล่าว ไม่มีทางอื่นอีกแล้วเหรอ?
carl

2
มันไม่ได้โง่เลย การนำเข้าสัมพัทธ์เป็นวิธีการอ้างอิงถึงโมดูล sibling ภายในแพ็คเกจ หากคุณต้องการนำเข้าโมดูลระดับบนสุดให้ใช้การนำเข้าแบบสัมบูรณ์
เฟอร์ดินานด์เบเยอร์

58
ไม่งี่เง่า ดังนั้นในการทุบตีคุณไม่สามารถพูดกับ dir ที่สัมพันธ์กับ ".. " จะไม่รบกวนคุณใช่ไหม
E-satis

2
สำหรับฉันแล้วความคิดของงูใหญ่คือการนำเข้า "สมบูรณ์" จากไดเรกทอรีที่คุณเปิดใช้งานสคริปต์หลักของคุณ ดังนั้นคุณสามารถใช้พา ธ สัมบูรณ์ "นำเข้าพาเรนต์" เพื่อนำเข้าโมดูลพาเรนต์จาก sibling และญาติ ๆ ก็นำเข้ามรดกบางอย่างหรืออะไรก็ตาม ..
Odysseus

35

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

# Add this line to the beginning of relative.py file
import sys
sys.path.append('..')

# Now you can do imports from one directory top cause it is in the sys.path
import parent

# And even like this:
from parent import Parent

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

sys.path.append(sys.path[0] + "/..")

sys.path[0] อ้างถึงเส้นทางที่จุดเข้าใช้งาน


3

ตรวจสอบมันใน python3:

python -V
Python 3.6.5

example1:

.
├── parent.py
├── start.py
└── sub
    └── relative.py

- start.py
import sub.relative

- parent.py
print('Hello from parent.py')

- sub/relative.py
from .. import parent

หากเราเรียกใช้เช่นนี้ (เพื่อให้แน่ใจว่า PYTHONPATH ว่างเปล่า):

PYTHONPATH='' python3 start.py

เอาท์พุท:

Traceback (most recent call last):
  File "start.py", line 1, in <module>
    import sub.relative
  File "/python-import-examples/so-example-v1/sub/relative.py", line 1, in <module>
    from .. import parent
ValueError: attempted relative import beyond top-level package

หากเราเปลี่ยนการนำเข้า sub/relative.py

- sub/relative.py
import parent

ถ้าเราวิ่งแบบนี้:

PYTHONPATH='' python3 start.py

เอาท์พุท:

Hello from parent.py

example2:

.
├── parent.py
└── sub
    ├── relative.py
    └── start.py

- parent.py
print('Hello from parent.py')

- sub/relative.py
print('Hello from relative.py')

- sub/start.py
import relative
from .. import parent

เรียกใช้เช่น:

PYTHONPATH='' python3 sub/start.py

เอาท์พุท:

Hello from relative.py
Traceback (most recent call last):
  File "sub/start.py", line 2, in <module>
    from .. import parent
ValueError: attempted relative import beyond top-level package

หากเราเปลี่ยนการนำเข้า sub/start.py :

- sub/start.py
import relative
import parent

เรียกใช้เช่น:

PYTHONPATH='' python3 sub/start.py

เอาท์พุท:

Hello from relative.py
Traceback (most recent call last):
  File "sub/start.py", line 3, in <module>
    import parent
ModuleNotFoundError: No module named 'parent'

เรียกใช้เช่น:

PYTHONPATH='.' python3 sub/start.py

เอาท์พุท:

Hello from relative.py
Hello from parent.py

นอกจากนี้ควรใช้การนำเข้าจากโฟลเดอร์รูทเช่น:

- sub/start.py
import sub.relative
import parent

เรียกใช้เช่น:

PYTHONPATH='.' python3 sub/start.py

เอาท์พุท:

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