นำเข้าโมดูลจากเส้นทางสัมพัทธ์


759

ฉันจะนำเข้าโมดูล Python ที่กำหนดเส้นทางสัมพัทธ์ได้อย่างไร

ตัวอย่างเช่นหากdirFooมีFoo.pyและdirBarและdirBarมีBar.pyฉันจะนำBar.pyเข้าได้Foo.pyอย่างไร

นี่คือการแสดงภาพ:

dirFoo\
    Foo.py
    dirBar\
        Bar.py

Fooต้องการรวมBarแต่การปรับโครงสร้างลำดับชั้นของโฟลเดอร์ไม่ใช่ตัวเลือก


2
ดูเหมือนว่าstackoverflow.com/questions/72852/…อาจจะใช่ไหม
Joril

3
ตรวจสอบคำตอบของฉันมันสมบูรณ์ที่สุดจนถึงขณะนี้คนอื่นไม่ทำงานในกรณีพิเศษตัวอย่างเช่นเมื่อคุณเรียกใช้สคริปต์จากไดเรกทอรีอื่นหรือจากสคริปต์หลามอื่น ดูstackoverflow.com/questions/279237/…
โซริน

ฉันมีปัญหาที่คล้ายกันและฉันพบสิ่งนี้และใช้งานได้ !! apt-get install python-profiler
ldcl289

5
ในกรณีที่ใครบางคนต้องการที่จะทำแบบคงที่และมาที่นี่ (เช่นฉัน :) คุณยังสามารถตั้งค่าตัวแปรสภาพแวดล้อม
PYTHONPATH

ดีกว่าคือการทำตามคำแนะนำใน Lib / site.py สำหรับแต่ละกรณี
Avenida Gez

คำตอบ:


333

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

ฉันคิดว่าคุณต้องการทำเช่นนี้เพราะคุณต้องรวมชุดของโมดูลเข้ากับสคริปต์ของคุณ ฉันใช้สิ่งนี้ในการผลิตในหลาย ๆ ผลิตภัณฑ์และทำงานในสถานการณ์พิเศษหลายอย่างเช่น: สคริปต์ที่เรียกจากไดเรกทอรีอื่นหรือดำเนินการด้วย python ที่รันแทนการเปิดล่ามใหม่

 import os, sys, inspect
 # realpath() will make your script run, even if you symlink it :)
 cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]))
 if cmd_folder not in sys.path:
     sys.path.insert(0, cmd_folder)

 # Use this if you want to include modules from a subfolder
 cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"subfolder")))
 if cmd_subfolder not in sys.path:
     sys.path.insert(0, cmd_subfolder)

 # Info:
 # cmd_folder = os.path.dirname(os.path.abspath(__file__)) # DO NOT USE __file__ !!!
 # __file__ fails if the script is called in different ways on Windows.
 # __file__ fails if someone does os.chdir() before.
 # sys.argv[0] also fails, because it doesn't not always contains the path.

โบนัสวิธีนี้จะช่วยให้คุณบังคับให้ Python ใช้โมดูลแทนโมดูลที่ติดตั้งไว้ในระบบ

คำเตือน! ฉันไม่รู้จริงๆว่าเกิดอะไรขึ้นเมื่อโมดูลปัจจุบันอยู่ในeggไฟล์ มันอาจล้มเหลวเช่นกัน


5
ฉันจะขอคำอธิบายเกี่ยวกับการทำงานของมันได้อย่างไร? ฉันมีปัญหาที่คล้ายกันและฉันชอบที่จะบังคับให้ DIR โมดูลหลามแทนที่จะวิ่งการค้นหา
คาร์ล crott

ใช้ Win 7 Pro 64x และ Python 2.7 ฉันได้รับข้อผิดพลาดเล็กน้อย 1) ฉันต้องเพิ่มการตรวจสอบไปยังรายการนำเข้า 2) ค่าที่ 1 [0] ใน tuple เป็นสตริงว่าง ที่ 2, [1], แสดงชื่อไฟล์ ฉันเดาว่าสิ่งแรกควรเป็นเส้นทาง ... ความคิดใด ๆ
อดัมเลวิส

2
ถ้าคุณจะไปสำหรับโฟลเดอร์ย่อยใช้มันเช่นนี้os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]) + "/subfolder")ทำไม่เพิ่มโฟลเดอร์ย่อยก่อนabspathเช่นนี้ทำให้เกิดข้อบกพร่องร้ายแรง
Maximilian Hils

4
@ scr4ve คุณควรใช้ os.path.join () แทนและคุณสามารถเพิ่มเคส ( cmd_subfolder) ลงในคำตอบของฉันได้โดยตรง ขอบคุณ!
sorin

7
สำหรับฉันแล้วสร้างเส้นทางแน่นอนดังนั้นฉันไม่จำเป็นต้องrealpath abspathนอกจากนี้ยังos.path.dirnameสามารถใช้แทนการแยกทำให้การจัดทำดัชนี[0]ล้าสมัย แถวนั้นจะเป็น:os.path.realpath(os.path.dirname(inspect.getfile(inspect.currentframe())))
เท็ด

328

ตรวจสอบให้แน่ใจว่า dirBar มี__init__.pyไฟล์ซึ่งจะทำให้ไดเรคทอรีเป็นแพ็คเกจ Python


204
โปรดทราบว่าไฟล์นี้จะว่างเปล่าอย่างสมบูรณ์
Harley Holcombe

47
หากไดเรกทอรีแม่ dirBar ไม่ได้อยู่ในsys.pathแล้วการปรากฏตัวของ __init__.pyในdirBarไดเรกทอรีไม่ได้ช่วยมาก
jfs

7
-1 การเพิ่ม__init.py__จะใช้งานได้เฉพาะเมื่อไดเรกทอรีอยู่ใน sys.path อยู่แล้วและในกรณีของฉันมันไม่ใช่ โซลูชันโดย "sorin" (ยอมรับแล้ว) ใช้ได้ผลเสมอ
Czarek Tomczak

12
"เมื่อไดเรกทอรีอยู่ใน sys.path แล้ว". ในขณะที่เป็นจริงทั้งหมดเราจะเดาได้อย่างไรว่าไดเรกทอรีไม่ได้sys.pathมาจากคำถาม บางทีอาจมีบางอย่างที่เราไม่เห็นหรือไม่รู้
S.Lott

4
นี่คือโดย NO หมายถึงคำตอบสำหรับคำถาม: ไม่ว่าจะมีไฟล์ initialisation อยู่หรือไม่ไม่ทำให้งูหลามดูในไดเรกทอรีย่อย มันได้รับ upvotes หลายร้อยได้อย่างไร
เริ่ม

261

คุณสามารถเพิ่มไดเรกทอรีย่อยลงในพา ธ Python ของคุณเพื่อให้มันนำเข้าเป็นสคริปต์ปกติ

import sys
sys.path.insert(0, <path to dirFoo>)
import Bar

6
ดูเหมือนว่าคำตอบของคุณไม่ทำงานกับเส้นทางที่เกี่ยวข้องดูstackoverflow.com/questions/279237/…
bogdan

24
นี้จะทำงานร่วมกับทางญาติ - คุณเพียงแค่ต้องเข้าใจว่าทางญาติจะขึ้นอยู่กับสิ่งที่ไดเรกทอรีที่คุณทำงานจากที่นี้จะทำให้การแก้ปัญหาที่ดีสำหรับสิ่งอื่นที่ไม่ใช่สับอย่างรวดเร็ว
nobar

12
คุณสามารถทำสิ่งที่ชอบsys.path.append(os.path.dirname(__file__) + "/relative/path/to/module")
Falko

หรือsys.path.append(__name__ if __name__ != '__main__' else __loader__.fullname)
เป็นกลุ่ม

1
ลองใช้sys.path.insert(0, <path to dirFoo>)เพราะจะโหลดโมดูลนี้ก่อนโมดูลชื่อเดียวกันที่เก็บไว้ที่อื่น
Anton Tarasenko

117
import os
import sys
lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib'))
sys.path.append(lib_path)

import mymodule

2
ฉันชอบสิ่งนี้เพราะคุณมีความยืดหยุ่นในการขึ้นไดเรกทอรี
Charles L.

21
คุณควรใช้os.path.join()แทนการเข้าร่วมโดย '/' ซึ่งจะแตกในหน้าต่าง (อ่อนแอ)
0xc0de

18
สิ่งนี้ไม่น่าเชื่อถือ มันขึ้นอยู่กับสิ่งที่ไดเรกทอรีการทำงานปัจจุบันไม่ได้อยู่ในไดเรกทอรีที่สคริปต์อาศัยอยู่
jamesdlin

อาจต้องการเพิ่มเฉพาะในกรณีที่เส้นทางไม่ได้อยู่ในเส้นทาง lib_path = os.path.abspath ('../ function') ถ้า lib_path ไม่อยู่ใน sys.path: sys.path.append (lib_path)
Brent

ในการตอบกลับถึง @jamesdlin เป็นการรวมคำตอบสองสามข้อ: แล้วos.path.abspath(os.path.join(__file__,'..','lib'))ล่ะ?
Matthew Davis

107

เพียงทำสิ่งต่าง ๆ เพื่อนำเข้าไฟล์. py จากโฟลเดอร์อื่น

สมมติว่าคุณมีไดเรกทอรีเช่น:

lib/abc.py

จากนั้นให้เก็บไฟล์ว่างไว้ในโฟลเดอร์ lib ตามชื่อ

__init__.py

และจากนั้นใช้

from lib.abc import <Your Module name>

เก็บ__init__.pyไฟล์ในทุกโฟลเดอร์ของลำดับชั้นของโมดูลนำเข้า


79

หากคุณจัดโครงสร้างโครงการด้วยวิธีนี้:

src\
  __init__.py
  main.py
  dirFoo\
    __init__.py
    Foo.py
  dirBar\
    __init__.py
    Bar.py

จาก Foo.py คุณควรจะทำ:

import dirFoo.Foo

หรือ:

from dirFoo.Foo import FooObject

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


นอกจากนี้ยังกล่าวถึงinit .py จะถูกนำเข้าเมื่อโมดูลแรกที่อยู่ภายในแพ็คเกจนั้นถูกนำเข้า นอกจากนี้ตัวอย่างของคุณจะใช้งานได้ก็ต่อเมื่อ src อยู่ใน site_packages (หรือในเส้นทางการค้นหา)
Tom Leys

3
นี่เป็นทางออกที่ง่ายที่สุดที่ฉันต้องการ หากไฟล์ที่จะนำเข้าแน่ใจว่าอยู่ในหนึ่งในไดเรกทอรีย่อยโซลูชันนี้เป็นอัญมณี
Deepak GM

ฉันลองสิ่งเดียวกันและล้มเหลว ฉันไม่รู้ว่าทำไม. ImportError: ไม่มีโมดูลชื่อ customMath
Ming Li

9
เหตุใดจึงมีคนต้องการนำเข้า Foo จากภายใน Foo.py ตัวเอง ควรมาจาก Bar.py ฉันเดา
bhaskarc

from dirFoo import FooFoo.bla()ที่จะบอกว่า หากใช้import dirFoo.Fooควรใช้dirFoo.Foo.bla()- สวยน่าเกลียดแม้ไม่มีกรณีอูฐ
Cees Timmerman

45

วิธีที่ง่ายที่สุดคือการใช้ sys.path.append ()

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

# mod_name is the filename without the .py/.pyc extention
py_mod = imp.load_source(mod_name,filename_path) # Loads .py file
py_mod = imp.load_compiled(mod_name,filename_path) # Loads .pyc file 

สิ่งนี้สามารถใช้เพื่อโหลดโมดูลแบบไดนามิกเมื่อคุณไม่ทราบชื่อของโมดูล

ฉันเคยใช้สิ่งนี้ในอดีตเพื่อสร้างส่วนต่อประสานประเภทปลั๊กอินไปยังแอปพลิเคชันซึ่งผู้ใช้จะเขียนสคริปต์ด้วยฟังก์ชั่นเฉพาะแอปพลิเคชันและเพียงวางสคริปต์ของพวกเขาลงในไดเรกทอรีเฉพาะ

นอกจากนี้ฟังก์ชั่นเหล่านี้อาจมีประโยชน์:

imp.find_module(name[, path])
imp.load_module(name, file, pathname, description)

โปรดทราบว่าในเอกสาร imp.load_source และ imp.load_compiled มีการระบุไว้ว่าล้าสมัย แนะนำให้ใช้ imp.find_module และ imp.load_module แทน
amicitas

@ arimaitas คุณช่วยกรุณาอ้างอิงใด ๆ (ฉันต้องการมันและฉันใช้ python 2.6. ฉันรู้ว่า 2.7 docs พูดเกี่ยวกับสิ่งเหล่านี้ แต่ไม่สามารถหาอ้างอิงใด ๆ ที่เกี่ยวข้องกับ 2.6)
0xc0de

@ 0xc0de คุณสามารถค้นหาคำสั่งในเอกสารที่สำหรับโมดูลสำหรับทั้งภูตผีปีศาจงูหลาม 2.7.3และงูหลาม 2.6.7 ดูเหมือนว่าฟังก์ชั่นเหล่านั้นไม่ได้อยู่ใน docs สำหรับ python 3.2
amicitas

1
สำหรับการนำเข้าไฟล์ต้นฉบับใน python 3.3 ดูการนำเข้าไฟล์ต้นฉบับไพ ธ อน (Python 3.3 หรือสูงกว่า) - กองมากเกิน ขอบคุณผู้คนสำหรับเคล็ดลับที่นี่
nealmcb

44

นี่คือ PEP ที่เกี่ยวข้อง:

http://www.python.org/dev/peps/pep-0328/

โดยเฉพาะอย่างยิ่งการสันนิษฐาน dirFoo เป็นไดเรกทอรีขึ้นจาก dirBar ...

ใน dirFoo \ Foo.py:

from ..dirBar import Bar

มันใช้งานได้สำหรับฉันเพิ่งเพิ่มinit .py ในทุก ๆ โฟลเดอร์และนำเข้าสำเร็จ
yussan

23

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

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

เพิ่งรัน:

export PYTHONPATH=/absolute/path/to/your/module

คุณ sys.path จะมีเส้นทางด้านบนดังที่แสดงด้านล่าง:

print sys.path

['', '/absolute/path/to/your/module', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pymodules/python2.7', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client', '/usr/lib/python2.7/dist-packages/ubuntuone-client', '/usr/lib/python2.7/dist-packages/ubuntuone-control-panel', '/usr/lib/python2.7/dist-packages/ubuntuone-couch', '/usr/lib/python2.7/dist-packages/ubuntuone-installer', '/usr/lib/python2.7/dist-packages/ubuntuone-storage-protocol']

13

ในความคิดของฉันตัวเลือกที่ดีที่สุดคือใส่__ init __.pyในโฟลเดอร์และเรียกไฟล์ด้วย

from dirBar.Bar import *

ไม่แนะนำให้ใช้ sys.path.append () เพราะอาจมีบางอย่างผิดพลาดหากคุณใช้ชื่อไฟล์เดียวกับแพคเกจหลามที่มีอยู่ ฉันไม่ได้ทดสอบ แต่จะคลุมเครือ


แปลกที่from dirBar.Bar import *ทำงาน from dirBar.Bar import Barแต่ไม่ได้ คุณรู้หรือไม่ว่าทำไม * ถึงได้ผล? ถ้าฉันมีไฟล์หลายไฟล์ใน dirBar / และต้องการที่จะคว้าไฟล์เหล่านั้นเพียงไม่กี่ไฟล์ (ใช้วิธีการเช่นเดียวกับที่คุณโพสต์ที่นี่)
ผู้ทดสอบ

2
@tester: from dirBar import Barใช้
สูงศักดิ์

@tester เป็นเพราะตัวfromบ่งชี้แหล่งที่มาและทุกอย่างหลังจากนั้นimportคือสิ่งที่จะคว้าจากแหล่งที่มา from dirBar.Bar import Barหมายถึง "จากแหล่งที่มานำเข้าแหล่งที่มาของตัวเอง" ซึ่งไม่สมเหตุสมผล *แต่หมายถึง "ให้ฉันทุกอย่างจากแหล่งที่มา"
FuriousFolder

11

วิธีที่รวดเร็วและสกปรกสำหรับผู้ใช้ Linux

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

ln -s (path)/module_name.py

หรือ

ln -s (path)/package_name

หมายเหตุ: "โมดูล" คือไฟล์ใด ๆ ที่มีนามสกุล. py และ "แพ็คเกจ" คือโฟลเดอร์ใด ๆ ที่มีไฟล์__init__.py(ซึ่งอาจเป็นไฟล์ว่าง) จากมุมมองการใช้งานโมดูลและแพ็กเกจจะเหมือนกัน - ทั้งเปิดเผย "คำจำกัดความและคำสั่ง" ที่มีอยู่ตามที่ร้องขอผ่านimportคำสั่ง

ดู: http://docs.python.org/2/tutorial/modules.html


10
from .dirBar import Bar

แทน:

from dirBar import Bar

ในกรณีที่อาจมี dirBar อื่นติดตั้งอยู่และทำให้โปรแกรมอ่าน foo.py สับสน


2
ฉันทำสิ่งนี้บน windows ไม่ได้ อยู่บน Linux หรือไม่
Gabriel

1
มันจะทำงานจากสคริปต์ที่นำเข้า Foo เช่น: main.py นำเข้า dirFoo.Foo หากคุณพยายามเรียกใช้ Foo.py เป็นสคริปต์สคริปต์จะล้มเหลว ดูstackoverflow.com/questions/72852/…
jgomo3

9

สำหรับกรณีนี้เพื่อนำเข้า Bar.py ไปที่ Foo.py ก่อนอื่นฉันจะเปลี่ยนโฟลเดอร์เหล่านี้เป็นแพ็คเกจ Python ดังนี้:

dirFoo\
    __init__.py
    Foo.py
    dirBar\
        __init__.py
        Bar.py

จากนั้นฉันจะทำเช่นนี้ใน Foo.py:

from .dirBar import Bar

ถ้าฉันต้องการให้การกำหนดเนมให้ดูเหมือน Bar อะไรก็ตามหรือ

from . import dirBar

หากฉันต้องการเนมสเปซ dirBar.Bar อะไรก็ตาม เคสที่สองนี้มีประโยชน์หากคุณมีโมดูลเพิ่มเติมภายใต้แพ็กเกจ dirBar


7

เพิ่มไฟล์__init__.py :

dirFoo\
    Foo.py
    dirBar\
        __init__.py
        Bar.py

จากนั้นเพิ่มรหัสนี้ไปที่จุดเริ่มต้นของ Foo.py:

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

5
ถ้าdirBarมีอยู่แล้วเป็นแพคเกจหลาม (โดยการดำรงอยู่ของdirBar/__init__.py) ไม่มีความจำเป็นที่จะผนวกdirBarการsys.pathไม่? ข้อความimport BarจากFoo.pyควรเพียงพอ
Santa

5

ตัวอย่าง sys.path แบบสัมพันธ์:

# /lib/my_module.py
# /src/test.py


if __name__ == '__main__' and __package__ is None:
    sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../lib')))
import my_module

บนพื้นฐานนี้คำตอบ


5

อย่างที่คุณพูดถึงโดยปกติแล้วคุณต้องการเข้าถึงโฟลเดอร์ที่มีโมดูลของคุณซึ่งสัมพันธ์กับที่ที่สคริปต์หลักของคุณทำงานอยู่ดังนั้นคุณเพียงแค่นำเข้ามัน

สารละลาย:

ฉันมีสคริปต์ในD:/Books/MyBooks.pyและบางโมดูล (เช่น oldies.py) ฉันต้องการนำเข้าจากไดเรกทอรีย่อยD:/Books/includes:

import sys,site
site.addsitedir(sys.path[0] + '\\includes')
print (sys.path)  # Just verify it is there
import oldies

ใส่ลงprint('done')ในoldies.pyเพื่อให้คุณตรวจสอบทุกอย่างจะตกลง วิธีนี้ใช้งานได้เสมอเนื่องจากคำจำกัดความของ Python sys.pathดังที่เริ่มต้นเมื่อเริ่มต้นโปรแกรมรายการแรกของรายการนี้path[0]คือไดเรกทอรีที่มีสคริปต์ที่ใช้ในการเรียกใช้ Python interpreter

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


1
ผมต้องใช้หนึ่งทับแทนของทั้งสองทับขวา (คือsite.addsitedir(sys.path[0]+'/includes')) ในโปรแกรมง่ายหลาม break_time.py ครั้งแรกของฉัน: https://github.com/ltfschoen/PythonTest ฉันใช้ระบบ: MacOS v10.11.5, Python 2.7.12, IDLE IDE 2.7.12, Tk 8.5.9
Luke Schoen

4

เพียงคุณสามารถใช้: from Desktop.filename import something

ตัวอย่าง:

เนื่องจากไฟล์นั้นเป็นชื่อtest.pyในไดเรกทอรี Users/user/Desktopและจะนำเข้าทุกอย่าง

รหัส:

from Desktop.test import *

แต่ให้แน่ใจว่าคุณสร้างไฟล์ว่างที่เรียกว่า " __init__.py" ในไดเรกทอรีนั้น


1
ห้ามนำเข้าที่ติดดาว ดู: stackoverflow.com/questions/2386714/why-is-import-bad
axolotl

ฉันรู้ว่าทำไมฉันก่อนเขียนimport somethingแล้วฉันพูดเพื่อให้ง่ายขึ้น* โดยทั่วไปมันไม่ดีสำหรับ ram และถ้า 2 ฟังก์ชั่นมีชื่อเดียวกันมันจะมวลรหัสของคุณ
0x1996

3

วิธีแก้ปัญหาอื่นก็คือการติดตั้งแพ็คเกจpy-requireจากนั้นใช้สิ่งต่อไปนี้ในFoo.py

import require
Bar = require('./dirBar/Bar')

URL ดูเหมือนว่าจะเป็นpypi.org/project/require.pyและโปรดทราบว่าจะต้องติดตั้งผ่าน Pip
Flash Sheridan

1
@FlashSheridan Nope นั่นเป็นโครงการที่แตกต่าง ฉันลบ py-need เนื่องจากฉันแน่ใจว่าไม่มีใครใช้มันฉันไม่ได้คิดถึงโพสต์นี้ หากคุณยังต้องการrequire()ฟังก์ชันคุณสามารถดูโครงการ Node.py ของฉัน: github.com/nodepy/nodepy
Niklas R

2

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

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

#to import from one level above:
cwd = os.getcwd()
os.chdir("..")
below_path =  os.getcwd()
sys.path.append(below_path)
os.chdir(cwd)

1
ฉันไม่เข้าใจคุณตรรกะที่นี่ มันซับซ้อนเกินไป
transilvlad

0

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

project\
    module_1.py 
    module_2.py

module_1.pyกำหนดฟังก์ชั่นที่เรียกว่าfunc_1(), module_2.py :

from module_1 import func_1

def func_2():
    func_1()

if __name__ == '__main__':
    func_2()

และคุณเรียกใช้หน่วยเป็นpython module_2.pycmd มันจะทำงานตามที่func_1()กำหนด ปกติแล้วเราจะนำเข้าไฟล์ลำดับชั้นเดียวกัน แต่เมื่อคุณเขียนfrom .module_1 import func_1ในหลามล่ามจะบอกว่าmodule_2.py No module named '__main__.module_1'; '__main__' is not a packageเพื่อแก้ไขปัญหานี้เราเพียง แต่ทำการเปลี่ยนแปลงที่เราเพิ่งทำและย้ายโมดูลทั้งสองไปยังแพ็คเกจและทำให้โมดูลที่สามเป็นผู้เรียกเพื่อให้ทำงานmodule_2.pyได้

project\
    package_1\
        module_1.py
        module_2.py
    main.py

main.py :

from package_1.module_2 import func_2

def func_3():
    func_2()

if __name__ == '__main__':
    func_3()

แต่เหตุผลที่เราเพิ่ม.ก่อนmodule_1ในmodule_2.pyคือว่าถ้าเราไม่ทำอย่างนั้นและเรียกmain.pyหลามล่ามจะบอกNo module named 'module_1'ว่าเป็นเรื่องยุ่งยากเล็กน้อยข้างขวาmodule_1.py module_2.pyตอนนี้ผมให้func_1()ในmodule_1.pyบางสิ่งบางอย่างที่ต้องทำ:

def func_1():
    print(__name__)

ที่__name__บันทึกที่เรียก func_1 ตอนนี้เราเก็บ.ก่อนที่จะmodule_1วิ่งmain.pyก็จะพิมพ์ไม่package_1.module_1 module_1มันบ่งชี้ว่าผู้ที่โทรfunc_1()อยู่ในลำดับชั้นเดียวกันกับmain.pyที่.บ่งบอกว่าmodule_1อยู่ในลำดับชั้นเดียวกับmodule_2.pyตัวเอง ดังนั้นหากไม่มีจุดmain.pyจะรับรู้module_1ในลำดับชั้นเดียวกันกับตัวเองมันสามารถรับรู้package_1แต่ไม่ใช่สิ่งที่ "ภายใต้" มัน

ทีนี้มาทำให้มันซับซ้อนหน่อย คุณมีconfig.iniและโมดูลกำหนดฟังก์ชั่นให้อ่านในลำดับชั้นเดียวกับ 'main.py'

project\
    package_1\
        module_1.py
        module_2.py
    config.py
    config.ini
    main.py

และด้วยเหตุผลที่หลีกเลี่ยงไม่ได้บางอย่างคุณต้องโทรหาด้วยmodule_2.pyดังนั้นจึงต้องนำเข้าจากลำดับชั้นด้านบน module_2.py :

 import ..config
 pass

สองจุดหมายถึงนำเข้าจากลำดับชั้นบน (จุดสามจุดเข้าถึงด้านบนกว่าบนและอื่น ๆ ) ตอนนี้เราทำงานล่ามจะพูดว่า:main.py ValueError:attempted relative import beyond top-level package"การแพคเกจระดับบนสุด" main.pyที่นี่คือ เพียงเพราะconfig.pyอยู่ข้างmain.pyพวกเขาอยู่ในลำดับชั้นเดียวกันconfig.pyไม่ได้ "ภายใต้" main.pyหรือมันไม่ได้เป็น "สารตะกั่ว" โดยดังนั้นจึงอยู่นอกเหนือmain.py main.pyในการแก้ไขปัญหานี้วิธีที่ง่ายที่สุดคือ:

project\
    package_1\
        module_1.py
        module_2.py
    config.py
    config.ini
main.py

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


-5

สิ่งนี้ยังใช้งานได้และง่ายกว่าsysโมดูลใด ๆ :

with open("C:/yourpath/foobar.py") as f:
    eval(f.read())

1
ถ้า OP กำลังจะฮาร์ดโค้ดพา ธ พวกเขาสามารถแทรกพา ธ นั้นลงใน PYTHONPATH ได้ ฉันคิดว่าประเด็นนี้กำลังทำอยู่ในลักษณะที่ไม่ฮาร์ดโค้ดพา ธ เนื่องจากมันจะแตกที่อื่น
แมทธิว

-15

โทรหาฉันด้วยความระมัดระวังมากเกินไป แต่ฉันชอบที่จะทำให้ฉันพกพาสะดวกกว่าเดิมเพราะไม่ปลอดภัยที่จะสมมติว่าไฟล์จะอยู่ในที่เดียวกันกับคอมพิวเตอร์ทุกเครื่อง ส่วนตัวฉันมีรหัสค้นหาเส้นทางไฟล์ก่อน ฉันใช้ Linux ดังนั้นฉันจะมีลักษณะเช่นนี้:

import os, sys
from subprocess import Popen, PIPE
try:
    path = Popen("find / -name 'file' -type f", shell=True, stdout=PIPE).stdout.read().splitlines()[0]
    if not sys.path.__contains__(path):
        sys.path.append(path)
except IndexError:
    raise RuntimeError("You must have FILE to run this program!")

แน่นอนว่าถ้าคุณไม่ได้วางแผนที่จะจัดแพ็คเกจเหล่านี้ด้วยกัน แต่ถ้าเป็นกรณีนี้คุณไม่จำเป็นต้องแยกสองไฟล์จริงๆ


11
ไม่มีประสิทธิภาพมาก!
0xc0de

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