การนำเข้าโมดูลจากโฟลเดอร์หลัก


624

ฉันกำลังใช้ Python 2.5

นี่คือแผนผังโฟลเดอร์ของฉัน:

ptdraft/
  nib.py
  simulations/
    life/
      life.py

(ฉันยังมี__init__.pyในแต่ละโฟลเดอร์โดยไม่ต้องอ่านค่าที่นี่)

ฉันจะนำเข้าnibโมดูลจากภายในlifeโมดูลได้อย่างไร ฉันหวังว่ามันเป็นไปได้ที่จะทำโดยไม่ต้องซ่อมแซมด้วย sys.path

หมายเหตุ: โมดูลหลักที่กำลังทำงานอยู่ในptdraftโฟลเดอร์


1
การตั้งค่า PYTHONPATH ของคุณคืออะไร
S.Lott

2
Ross: ฉันมองไปที่นั่น ฉันควรทำอย่างไรเกี่ยวกับเรื่องนี้? __init__.pyผมมีอยู่แล้ว S.Lott: ผมไม่ทราบวิธีการตรวจสอบ ...
ราม Rachum

4
echo $ PYTHONPATH จากเชลล์; sys นำเข้า; พิมพ์ sys.path จากภายใน Python docs.python.org/tutorial/…
S.Lott

@FlipMcF Google เป็นเครื่องมือค้นหาฟองดังนั้นความจริงที่ว่าผลลัพธ์นี้ค่อนข้างสูงสำหรับคุณไม่สำคัญ ที่สำคัญกว่านั้นคือความจริงที่ว่า DuckDuckGo เป็นเสิร์ชเอ็นจิ้นที่ไม่มีฟอง
ArtOfWarfare

3
ผมขอแนะนำให้ข้ามผ่านมาทั้งหมดsys.pathหรือPYTHONPATHคำตอบและการตรวจสอบจากคำตอบที่ดีเยี่ยมของ np8 ใช่มันอ่านมานาน ใช่มันดูเหมือนงานมาก แต่มันเป็นคำตอบเดียวที่แก้ปัญหาได้อย่างถูกต้องและเรียบร้อย
Aran-Fey

คำตอบ:


118

ดูเหมือนว่าปัญหาไม่เกี่ยวข้องกับโมดูลที่อยู่ในไดเรกทอรีหลักหรืออะไรทำนองนั้น

คุณต้องเพิ่มไดเรกทอรีที่มีptdraftPYTHONPATH

คุณบอกว่าใช้import nibงานได้กับคุณนั่นอาจหมายความว่าคุณเพิ่มptdraftตัวเอง (ไม่ใช่ผู้ปกครอง) ลงใน PYTHONPATH


15
การเพิ่มทุกอย่างลงใน pythonpath ไม่ใช่วิธีที่ดีถ้าคุณทำงานกับแพ็คเกจจำนวนมากที่ไม่เคยถูกนำมาใช้ซ้ำ
Jason Cheng

@ JasonCheng: แล้วทำไมพวกเขาแพคเกจ ?
Davis Herring

7
สำหรับฉันคำตอบนี้ได้ผล อย่างไรก็ตามเพื่อให้ชัดเจนยิ่งขึ้นขั้นตอนคือไปimport sysแล้วsys.path.append("..\<parent_folder>")
BCJuan

603

คุณสามารถใช้การนำเข้าแบบสัมพันธ์ (python> = 2.5):

from ... import nib

(มีอะไรใหม่ใน Python 2.5) PEP 328: การนำเข้าแบบสัมบูรณ์และแบบสัมพัทธ์

แก้ไข : เพิ่มอีกจุด '.' เพื่อขึ้นสองแพ็คเกจ


177
ValueError: Attempted relative import in non-package
endolith

18
@endolith: คุณต้องอยู่ในแพ็คเกจนั่นคือคุณต้องมีไฟล์init .py
kirbyfan64sos

31
พยายามนำเข้าที่เกี่ยวข้องเกินกว่าแพ็คเกจระดับบนสุด
ผู้ใช้

291
เพื่อให้แม่นยำยิ่งขึ้นคุณต้องมี__init__.pyไฟล์
kara deniz

17
โปรดดูคำตอบต่อไปนี้เนื่องจากการเพิ่ม__init__.pyไม่ใช่สิ่งเดียวที่คุณต้องทำ: stackoverflow.com/questions/11536764/…
Ben Farmer

286

การนำเข้าสัมพัทธ์ (ในfrom .. import mymodule) ทำงานเฉพาะในแพ็คเกจ วิธีนำเข้า 'mymodule' ที่อยู่ในไดเรกทอรีหลักของโมดูลปัจจุบันของคุณ:

import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir) 

import mymodule

แก้ไข : __file__แอตทริบิวต์ไม่ได้รับเสมอ แทนที่จะใช้os.path.abspath(__file__)ตอนนี้ฉันแนะนำให้ใช้โมดูลตรวจสอบเพื่อดึงชื่อไฟล์ (และพา ธ ) ของไฟล์ปัจจุบัน


97
สิ่งที่สั้นกว่าเล็กน้อย:sys.path.insert(1, os.path.join(sys.path[0], '..'))
JHolta

8
มีเหตุผลใดที่จะหลีกเลี่ยง sys.path.append () แทนการแทรก?
Tyler

2
@Tyler - มันอาจมีความสำคัญหากที่อื่นแล้วparentdirแต่ในหนึ่งในเส้นทางทั้งหมดที่ระบุไว้ในsys.pathมีโมดูลอื่นที่มีชื่อ 'mymodule' การแทรกparentdirเป็นองค์ประกอบแรกของsys.pathรายการรับรองว่าโมดูลจากparentdirจะถูกนำเข้าแทน
Remi

5
@JHolta หากคุณไม่ได้จัดการกับแพ็คเกจคุณเป็นทางออกที่ดีที่สุด
Jonathon Reinhart

5
@JHolta ความคิดที่ดี sys.path.insert(1, os.path.realpath(os.path.pardir))ทำงานเกินไป
SpeedCoder5

177

ฉันโพสต์คำตอบที่คล้ายกันกับคำถามเกี่ยวกับการนำเข้าจากแพ็คเกจพี่น้อง คุณสามารถดูได้ที่นี่

ทางออกที่ไม่มีsys.pathแฮ็ค

สรุป

  • ล้อมโค้ดไว้ในหนึ่งโฟลเดอร์ (เช่นpackaged_stuff)
  • ใช้สร้างsetup.pyสคริปต์ที่คุณใช้setuptools.setup ()
  • Pip ติดตั้งแพคเกจในสถานะที่แก้ไขได้ด้วย pip install -e <myproject_folder>
  • นำเข้าโดยใช้ from packaged_stuff.modulename import function_name

ติดตั้ง

ฉันถือว่าโครงสร้างโฟลเดอร์เดียวกับในคำถาม

.
└── ptdraft
    ├── __init__.py
    ├── nib.py
    └── simulations
        ├── __init__.py
        └── life
            ├── __init__.py
            └── life.py

ที่ผมเรียกว่าโฟลเดอร์รากและในกรณีของฉันมันตั้งอยู่ใน.C:\tmp\test_imports

ขั้นตอน

1) เพิ่ม a setup.pyไปยังโฟลเดอร์รูท

เนื้อหาของsetup.pyสามารถเป็นเพียง

from setuptools import setup, find_packages

setup(name='myproject', version='1.0', packages=find_packages())

โดยทั่วไป "ใด ๆ " setup.pyจะทำงาน นี่เป็นเพียงตัวอย่างการทำงานที่น้อยที่สุด

2) ใช้สภาพแวดล้อมเสมือน

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

  • สร้าง env เสมือน
    • python -m venv venv
  • เปิดใช้งาน env เสมือน
    • . /venv/bin/activate(Linux) หรือ./venv/Scripts/activate(Win)

หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับสิ่งนี้เพียงแค่ Google "python virtualenv tutorial" หรือที่คล้ายกัน คุณอาจไม่ต้องการคำสั่งอื่นใดนอกจากสร้างเปิดใช้งานและปิดใช้งาน

เมื่อคุณสร้างและเปิดใช้งานสภาพแวดล้อมเสมือนจริงแล้วคอนโซลของคุณควรให้ชื่อของสภาพแวดล้อมเสมือนในวงเล็บ

PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>

3) pip ติดตั้งโครงการของคุณในสถานะที่แก้ไขได้

ติดตั้งแพคเกจระดับบนสุดของคุณโดยใช้myproject pipเคล็ดลับคือการใช้การ-eตั้งค่าสถานะเมื่อทำการติดตั้ง วิธีนี้จะถูกติดตั้งในสถานะที่แก้ไขได้และการแก้ไขทั้งหมดที่ทำกับไฟล์. py จะรวมอยู่ในแพ็คเกจที่ติดตั้งโดยอัตโนมัติ

ในไดเรกทอรีรากให้เรียกใช้

pip install -e . (สังเกตจุดนั้นย่อมาจาก "ไดเรกทอรีปัจจุบัน")

คุณสามารถเห็นว่ามันถูกติดตั้งโดยใช้ pip freeze

(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///C:/tmp/test_imports
Installing collected packages: myproject
  Running setup.py develop for myproject
Successfully installed myproject
(venv) PS C:\tmp\test_imports> pip freeze
myproject==1.0

4) นำเข้าโดยต่อท้ายmainfolderทุกการนำเข้า

ในตัวอย่างนี้จะเป็นmainfolder ptdraftนี่เป็นข้อดีที่คุณจะไม่พบในการชนชื่อกับชื่อโมดูลอื่น (จากไลบรารีมาตรฐานของไพ ธ อนหรือโมดูลบุคคลที่สาม)


ตัวอย่างการใช้งาน

nib.py

def function_from_nib():
    print('I am the return value from function_from_nib!')

life.py

from ptdraft.nib import function_from_nib

if __name__ == '__main__':
    function_from_nib()

ใช้ life.py

(venv) PS C:\tmp\test_imports> python .\ptdraft\simulations\life\life.py
I am the return value from function_from_nib!

1
ทำไมจึงใช้งานได้ มันเปลี่ยน PYTHONPATH เบื้องหลังหรือไม่?
Homero Esmeraldo

2
นอกจากนี้เหตุใดจึงดีกว่าหรือสวยงามกว่าการใช้วิธี sys.path
Homero Esmeraldo

5
@HomeroBarrocasSEsmeraldo คำถามที่ดี PYTHONPATH env var ไม่ได้ถูกแตะต้อง สิ่งนี้จะติดตั้งลงในแพ็คเกจไซต์ซึ่งมีอยู่แล้วsys.pathและโดยทั่วไปผู้ใช้จะต้องติดตั้งรหัสใด นั่นดีกว่าsys.pathแฮ็ก (และคุณสามารถรวมการใช้ PYTHONPATH ในหมวดหมู่ของแฮ็กพา ธ นั้น) เพราะมันหมายถึงรหัสในการพัฒนาควรทำแบบเดียวกับที่คุณทำกับผู้ใช้รายอื่น ในทางตรงกันข้ามเมื่อใช้การปรับเปลี่ยนพา ธ ข้อความสั่งการนำเข้าจะได้รับการแก้ไขด้วยวิธีอื่น
wim

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

2
ทำไมการทำให้หลามปวดหัวการนำเข้ามีความซับซ้อนมากขึ้น? เราต้องเขียนไฟล์ติดตั้ง, env เสมือน, ติดตั้ง pip หรือไม่? พระเจ้าช่วย!
Emerson Xu

68

คุณสามารถใช้ OS เส้นทางขึ้นอยู่ใน "เส้นทางการค้นหาโมดูล" ซึ่งมีการระบุไว้ในsys.path ดังนั้นคุณสามารถเพิ่มไดเรกทอรีหลักได้อย่างง่ายดายดังต่อไปนี้

import sys
sys.path.insert(0,'..')

ถ้าคุณต้องการเพิ่มไดเรกทอรีหลัก - พาเรนต์

sys.path.insert(0,'../..')

สิ่งนี้ใช้ได้ทั้งใน python 2 และ 3


6
สิ่งนี้สัมพันธ์กับไดเร็กทอรีปัจจุบันไม่จำเป็นต้องเป็นไดเร็กทอรีที่มีสคริปต์หลัก
Davis Herring

57

หากการเพิ่มโฟลเดอร์โมดูลของคุณไปยัง PYTHONPATH ไม่ทำงานคุณสามารถแก้ไขรายการsys.pathในโปรแกรมของคุณที่ Python interpreter ค้นหาโมดูลที่จะนำเข้าเอกสาร Pythonกล่าวว่า:

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

  • ไดเร็กทอรีที่มีสคริปต์อินพุต (หรือไดเร็กทอรีปัจจุบัน)
  • PYTHONPATH (รายการชื่อไดเรกทอรีที่มีไวยากรณ์เดียวกับตัวแปรเชลล์ PATH)
  • ค่าเริ่มต้นขึ้นอยู่กับการติดตั้ง

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

เมื่อรู้สิ่งนี้คุณสามารถทำสิ่งต่อไปนี้ในโปรแกรมของคุณ:

import sys
# Add the ptdraft folder path to the sys.path list
sys.path.append('/path/to/ptdraft/')

# Now you can import your module
from ptdraft import nib
# Or just
import ptdraft

6
คำตอบของคุณดี แต่อาจไม่ได้ผลเสมอไปและไม่สะดวกในการพกพา หากโปรแกรมถูกย้ายไปยังตำแหน่งใหม่/path/to/ptdraftจะต้องมีการแก้ไข มีวิธีแก้ไขปัญหาที่ทำงานกับไดเรกทอรีปัจจุบันของไฟล์และนำเข้าจากโฟลเดอร์หลักด้วยเช่นกัน
Edward

@Edward เทคนิคเหล่านั้นคืออะไร?
Shuklaswag

1
@Shuklaswag ตัวอย่างเช่นคำตอบstackoverflow.com/questions/714063/...
Edward

50

ไม่ทราบมากเกี่ยวกับ python 2
ใน python 3 สามารถเพิ่มโฟลเดอร์พาเรนต์ได้ดังนี้:

import sys 
sys.path.append('..')

... และจากนั้นหนึ่งสามารถนำเข้าโมดูลจากมัน


13
ใช้งานได้เฉพาะในกรณีที่ไดเรกทอรีการทำงานปัจจุบันของคุณเป็นแบบที่'..'นำไปสู่ไดเรกทอรีที่มีปัญหา
user5359531

31

นี่คือคำตอบที่ง่ายเพื่อให้คุณสามารถดูวิธีการทำงานขนาดเล็กและข้ามแพลตฟอร์ม
เพียงใช้ในตัวโมดูล ( os, sysและinspect) ดังนั้นควรจะทำงาน
บนระบบปฏิบัติการใด ๆ (OS) เพราะงูใหญ่ถูกออกแบบมาสำหรับการที่

รหัสย่อสำหรับคำตอบ - บรรทัดและตัวแปรน้อยลง

from inspect import getsourcefile
import os.path as path, sys
current_dir = path.dirname(path.abspath(getsourcefile(lambda:0)))
sys.path.insert(0, current_dir[:current_dir.rfind(path.sep)])
import my_module  # Replace "my_module" here with the module name.
sys.path.pop(0)

สำหรับสายน้อยกว่านี้แทนบรรทัดที่สองด้วยimport os.path as path, sys, inspect,
เพิ่มinspect.จุดเริ่มต้นของgetsourcefile(สาย 3) และลบบรรทัดแรก
- อย่างไรก็ตามสิ่งนี้นำเข้าโมดูลทั้งหมดดังนั้นอาจต้องใช้เวลามากขึ้นหน่วยความจำและทรัพยากร

รหัสสำหรับคำตอบของฉัน ( รุ่นที่ยาวกว่า )

from inspect import getsourcefile
import os.path
import sys

current_path = os.path.abspath(getsourcefile(lambda:0))
current_dir = os.path.dirname(current_path)
parent_dir = current_dir[:current_dir.rfind(os.path.sep)]

sys.path.insert(0, parent_dir)

import my_module  # Replace "my_module" here with the module name.

มันใช้ตัวอย่างจากคำตอบ Stack Overflow ฉันจะได้รับเส้นทางของ
ไฟล์ที่ดำเนินการปัจจุบันใน Python ได้อย่างไร
เพื่อค้นหาซอร์ส (ชื่อไฟล์) ของโค้ดที่รันด้วยเครื่องมือในตัว

from inspect import getsourcefile  
from os.path import abspath  

ถัดไปทุกที่ที่คุณต้องการค้นหาไฟล์ต้นฉบับจากคุณเพียงใช้:

abspath(getsourcefile(lambda:0))

รหัสของฉันเพิ่มเส้นทางของไฟล์เพื่อsys.pathที่หลามรายการเส้นทาง
นี้เพราะช่วยให้งูหลามโมดูลนำเข้าจากโฟลเดอร์ที่

หลังจากนำเข้าโมดูลในรหัสเป็นความคิดที่ดีที่จะรันsys.path.pop(0)บนบรรทัดใหม่
เมื่อโฟลเดอร์ที่เพิ่มนั้นมีโมดูลที่มีชื่อเดียวกันกับโมดูลอื่นที่นำเข้า
มาในโปรแกรม คุณต้องลบรายการที่เพิ่มก่อนการนำเข้าไม่ใช่เส้นทางอื่น
หากโปรแกรมของคุณไม่ได้นำเข้าโมดูลอื่น ๆ จะปลอดภัยที่จะไม่ลบพา ธ ของไฟล์เพราะ
หลังจากโปรแกรมสิ้นสุดลง (หรือรีสตาร์ทเชลล์ Python) การแก้ไขใด ๆ ที่ทำsys.pathหายไป

หมายเหตุเกี่ยวกับตัวแปรชื่อไฟล์

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

ตัวอย่างบางส่วนที่มันไม่ทำงาน (อ้างจากนี้คำถามกองมากเกิน):

ไม่พบในบางแพลตฟอร์ม•บางครั้งอาจไม่ใช่เส้นทางไฟล์แบบเต็ม

  • py2exeไม่มี__file__แอตทริบิวต์ แต่มีวิธีแก้ไขเฉพาะหน้า
  • เมื่อคุณเรียกใช้จาก IDLE โดยexecute()ไม่มี__file__แอตทริบิวต์
  • OS X 10.6 ที่ฉันได้รับ NameError: global name '__file__' is not defined

1
ฉันทำสิ่งนี้และลบรายการพา ธ ใหม่ด้วย sys.path.pop(0)ทันทีหลังจากนำเข้าโมดูลที่ต้องการ อย่างไรก็ตามการนำเข้าที่ตามมายังคงไปที่ตำแหน่งนั้น ตัวอย่างเช่นผมมีapp/config, และapp/tools app/submodule/configจากsubmoduleผมใส่app/จะนำเข้าtoolsแล้วเอาapp/และพยายามที่จะนำเข้าconfigแต่ฉันได้รับแทนapp/config app/submodule/config
user5359531

ฉันคิดว่าtoolsการนำเข้าอย่างใดอย่างหนึ่งก็กำลังนำเข้าconfigจากผู้ปกครองหลัก ดังนั้นเมื่อผมมาพยายามที่จะทำsys.path.pop(0); import configภายในsubmoduleคาดว่าจะได้รับ ผมได้รับจริงapp/submodule/config app/configPython ส่งกลับรุ่นที่แคชของโมดูลด้วยชื่อเดียวกันแทนที่จะตรวจสอบจริง ๆsys.pathสำหรับโมดูลที่ตรงกับชื่อนั้น sys.pathในกรณีนี้มีการเปลี่ยนแปลงอย่างถูกต้อง Python ไม่ได้ตรวจสอบเนื่องจากโมดูลที่มีชื่อเดียวกันนี้ได้ถูกโหลดแล้ว
user5359531

ฉันคิดว่านี่คือการอ้างอิงที่ถูกต้องกับปัญหาที่ฉันมี: docs.python.org/3/reference/import.html#the-module-cache
user5359531

ข้อมูลที่เป็นประโยชน์บางอย่างจาก5.3.1 แคชโมดูลในหน้าเอกสาร : ในระหว่างการนำเข้าชื่อโมดูลจะค้นหาในsys.modules ... sys.modules สามารถเขียนได้ การลบคีย์จะทำให้รายการแคชสำหรับโมดูลที่ระบุไม่ถูกต้องซึ่งทำให้ Python ค้นหาใหม่ตามการนำเข้าครั้งต่อไป ...ระวังแม้ว่าราวกับว่าคุณเก็บการอ้างอิงไปยังวัตถุโมดูลทำให้แคชใช้ไม่ได้จากนั้นนำเข้าอีกครั้งวัตถุทั้งสองจะแตกต่างกัน ในทางกลับกันimportlib.reload()จะนำมาใช้ซ้ำและกำหนดค่าเนื้อหาของโมดูลอีกครั้ง...
Edward

ยิ่งสั้นลง: os.path.realpath(getsourcefile(lambda:0) + "/../.."). จะได้รับไฟล์ต้นฉบับปัจจุบันต่อท้ายด้วยสัญลักษณ์ไดเรกทอรีหลักสองอัน ฉันไม่ได้ใช้os.path.sepเหมือนgetsourcefileเดิมส่งคืนสตริงที่ใช้/แม้กระทั่งบน Windows realpathจะดูแล popping off สองรายการไดเรกทอรีจากเส้นทางแบบเต็ม (ในกรณีนี้ชื่อไฟล์และไดเรกทอรีปัจจุบัน) ซึ่งให้ไดเรกทอรีหลัก
เบิร์น

28

นี่คือโซลูชันทั่วไปที่มีไดเร็กทอรีพาเรนต์ใน sys.path (ใช้ได้สำหรับฉัน):

import os.path, sys
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))

import os, sys\n sys.path.insert(0,os.path.pardir) สิ่งเดียวกัน แต่ sorther :) (ไม่มีการป้อนบรรทัดในความคิดเห็น)
Anti Veeranna

@antiveeranna ถ้าคุณใช้os.path.pardirคุณจะไม่ได้รับ realpath ของแม่เพียงญาติเส้นทางจากที่คุณกำลังเรียกsys.path.insert()
alvas

1
คำตอบนี้ใช้__file__ตัวแปรที่ไม่น่าเชื่อถือ (ไม่ใช่เส้นทางไฟล์แบบเต็มเสมอไปไม่สามารถใช้งานได้กับทุกระบบปฏิบัติการ ฯลฯ ) เนื่องจากผู้ใช้ StackOverflow ได้กล่าวถึงบ่อยครั้ง การเปลี่ยนคำตอบเป็นไม่รวมจะทำให้เกิดปัญหาน้อยลงและเข้ากันได้มากขึ้น สำหรับข้อมูลเพิ่มเติมโปรดดูที่stackoverflow.com/a/33532002/3787376
Edward

23

ฉันพบวิธีต่อไปนี้ใช้งานได้สำหรับการนำเข้าแพ็คเกจจากไดเรกทอรีหลักของสคริปต์ ในตัวอย่างฉันต้องการนำเข้าฟังก์ชั่นenv.pyจากapp.dbแพคเกจ

.
└── my_application
    └── alembic
        └── env.py
    └── app
        ├── __init__.py
        └── db
import os
import sys
currentdir = os.path.dirname(os.path.realpath(__file__))
parentdir = os.path.dirname(currentdir)
sys.path.append(parentdir)

ดังนั้นดีหนึ่งซับ:sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
juzzlin

การปรับเปลี่ยนsys.pathทั้งหมดเป็นความคิดที่ไม่ดี คุณจำเป็นต้องมีวิธีการบางอย่าง ( เช่น , PYTHONPATH) สำหรับห้องสมุดของคุณจะสามารถเข้าถึงอื่น ๆรหัส (หรืออื่น ๆ มันไม่ได้จริงๆห้องสมุด); แค่ใช้มันตลอดเวลา!
Davis Herring

14

โซลูชั่นดังกล่าวข้างต้นก็ใช้ได้ วิธีแก้ไขปัญหานี้ก็คือ

หากคุณต้องการนำเข้าทุกอย่างจากไดเรกทอรีระดับบนสุด จากนั้น

from ...module_name import *

นอกจากนี้หากคุณต้องการนำเข้าโมดูลใด ๆ จากไดเรกทอรีหลัก จากนั้น

from ..module_name import *

นอกจากนี้หากคุณต้องการนำเข้าโมดูลใด ๆ จากไดเรกทอรีหลัก จากนั้น

from ...module_name.another_module import *

วิธีนี้คุณสามารถนำเข้าวิธีการเฉพาะถ้าคุณต้องการ


6
ดูเหมือนว่าจะเป็นอย่างที่ควรจะเป็น แต่ด้วยเหตุผลบางอย่างสิ่งนี้ไม่ทำงานในลักษณะเดียวกับsys.path.appendแฮ็กข้างต้นและฉันไม่สามารถนำเข้า lib ของฉันเช่นนี้ นี่คือสิ่งที่ฉันพยายามทำก่อนเริ่ม google :) ตกลงมันเป็นอย่างนี้ValueError: attempted relative import beyond top-level package
juzzlin

10

สำหรับฉันผู้ที่สั้นที่สุดและผู้ที่ชื่นชอบในการเข้าถึงไดเรกทอรีหลักคือ:

sys.path.append(os.path.dirname(os.getcwd()))

หรือ:

sys.path.insert(1, os.path.dirname(os.getcwd()))

os.getcwd () ส่งคืนชื่อของไดเรกทอรีการทำงานปัจจุบัน os.path.dirname (directory_name) จะส่งคืนชื่อไดเรกทอรีสำหรับชื่อที่ส่งผ่าน

ที่จริงแล้วในความเห็นของฉันสถาปัตยกรรมโครงการ Python ควรทำในลักษณะที่ไม่มีโมดูลใดจากไดเรกทอรีลูกจะใช้โมดูลใด ๆ จากไดเรกทอรีหลัก หากสิ่งนี้เกิดขึ้นคุณควรคิดใหม่เกี่ยวกับแผนผังโครงการ

อีกวิธีหนึ่งคือการเพิ่มไดเรกทอรีหลักไปยังตัวแปรสภาพแวดล้อมระบบ PYTHONPATH


2
+1 สำหรับการพูดถึงความเป็นไปได้ที่จะต้องปรับโครงสร้างโครงการ (เมื่อเทียบกับการแฮ็กปัญหา)
semore_1267

สิ่งนี้ไม่ได้มาจากพ่อแม่ แต่จะได้รับกระแส
Ricky Levi

9

ในสมุดบันทึก Jupyter

ตราบใดที่คุณทำงานใน Jupyter Notebook โซลูชันระยะสั้นนี้อาจมีประโยชน์:

%cd ..
import nib

มันทำงานได้แม้ไม่มี__init__.pyไฟล์

ฉันทดสอบกับ Anaconda3 บน Linux และ Windows 7


2
มันจะไม่เหมาะสมที่จะเพิ่ม%cd -หลังจากการนำเข้าดังนั้นไดเรกทอรีปัจจุบันของสมุดบันทึกจะไม่เปลี่ยนแปลง
Dror


5

เมื่อไม่ได้อยู่ในสภาพแวดล้อมแพคเกจที่มี__init__.pyไฟล์ไลบรารี pathlib (รวมอยู่กับ> = Python 3.4) ทำให้มันกระชับและใช้งานง่ายเพื่อผนวกพา ธ ของพาเรนต์ไดเร็กทอรีไปยัง PYTHONPATH:

import sys
from pathlib import Path
sys.path.append(str(Path('.').absolute().parent))

เป็นไปได้หรือไม่ที่จะใช้init .py เพื่อหลีกเลี่ยงปัญหานี้?
ปัญญาประดิษฐ์

4

สไตล์เดียวกันกับคำตอบที่ผ่านมา - แต่มีจำนวนบรรทัดน้อยกว่า: P

import os,sys
parentdir = os.path.dirname(__file__)
sys.path.insert(0,parentdir)

file ส่งคืนตำแหน่งที่คุณกำลังทำงาน


สำหรับฉันไฟล์เป็นชื่อไฟล์ที่ไม่มีเส้นทางรวมอยู่ด้วย ฉันเรียกใช้โดยใช้ "ipy filename.py"
เคอร์ติส Yallop

สวัสดี @CurtisYallop ในตัวอย่างด้านบนเรากำลังเพิ่ม dir ที่มีไฟล์ [ที่เราอยู่ในปัจจุบัน] ที่ไฟล์ไพ ธ อนนั้นการเรียกใช้ os.path.dirname พร้อมชื่อไฟล์ควรส่งคืนพา ธ ของไฟล์และเรา กำลังเพิ่มนั่นลงในพา ธ ไม่ใช่ไฟล์อย่างชัดเจน -: HTH's :-)
YFP

คุณสมมติว่า __file__ มีเส้นทางรวมทั้งไฟล์เสมอ บางครั้งมันมีเพียงชื่อไฟล์ที่ไม่มีเส้นทาง
Curtis Yallop

@CurtisYallop - ไม่ใช่ทุกคนฉันถือว่าไฟล์เป็นชื่อไฟล์และฉันใช้ os.path.dirname () เพื่อรับพา ธ สำหรับไฟล์ คุณมีตัวอย่างของสิ่งนี้ไม่ทำงาน? ฉันจะรักขั้นตอนในการทำซ้ำ
YFP

1
@CurtisYallop - ไม่ฉันไม่ใช่! ฉันกำลังบอกว่า: พิมพ์/ _ / file / _ /จะให้ชื่อไฟล์ในตัวอย่างของคุณด้านบน "file.py" - ฉันกำลังบอกว่าคุณสามารถใช้ os.path.dirname () เพื่อดึงเส้นทางแบบเต็มจากที่ . หากคุณโทรมาจากสถานที่แปลก ๆ และคุณต้องการความสัมพันธ์แบบนั้นคุณสามารถค้นหา dir ที่ทำงานของคุณผ่านโมดูลระบบปฏิบัติการ - Jeez!
YFP

1

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


1
ความคิดของคุณดี แต่บางคนอาจต้องการรวมโมดูลของพวกเขาด้วยรหัสของพวกเขา - อาจจะทำให้มันเป็นแบบพกพาและไม่จำเป็นต้องใส่โมดูลของพวกเขาในsite-packagesทุกครั้งที่พวกเขาเรียกใช้บนคอมพิวเตอร์เครื่องอื่น
Edward

0

ในระบบ Linux คุณสามารถสร้างซอฟต์ลิงค์จากโฟลเดอร์ "life" ไปยังไฟล์ nib.py จากนั้นคุณสามารถนำเข้าเช่น:

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