Nhập một mô-đun từ một đường dẫn tương đối


759

Làm cách nào để nhập mô-đun Python theo đường dẫn tương đối của nó?

Ví dụ: nếu dirFoochứa Foo.pydirBar, và dirBarchứa Bar.py, làm cách nào để nhập Bar.pyvào Foo.py?

Đây là một đại diện trực quan:

dirFoo\
    Foo.py
    dirBar\
        Bar.py

Foomuốn bao gồm Bar, nhưng cấu trúc lại hệ thống phân cấp thư mục không phải là một lựa chọn.


2
Hình như stackoverflow.com/questions/72852/ , có lẽ vậy?
Joril

3
Kiểm tra câu trả lời của tôi, nó là hoàn chỉnh nhất cho đến nay, những người khác không làm việc trong trường hợp đặc biệt, ví dụ như khi bạn gọi tập lệnh từ thư mục khác hoặc từ tập lệnh python khác. Xem stackoverflow.com/questions/279237/ từ
sorin

Tôi đã có một vấn đề tương tự và tôi đã tìm thấy nó và nó hoạt động !! apt-get install python-profiler
ldcl289

5
Chỉ trong trường hợp ai đó muốn thực hiện tĩnh và đến đây (như tôi đã làm :) bạn cũng có thể thiết lập biến môi trường PYTHONPATH
okaram

Tốt hơn là làm theo các hướng dẫn trong Lib / site.py cho từng trường hợp
Avenida Gez

Câu trả lời:


333

Giả sử rằng cả hai thư mục của bạn là các gói Python thực sự (có __init__.py tệp bên trong chúng), đây là một giải pháp an toàn để đưa các mô-đun tương đối vào vị trí của tập lệnh.

Tôi giả sử rằng bạn muốn làm điều này, bởi vì bạn cần bao gồm một tập hợp các mô-đun với tập lệnh của bạn. Tôi sử dụng điều này trong sản xuất trong một số sản phẩm và hoạt động trong nhiều tình huống đặc biệt như: các tập lệnh được gọi từ một thư mục khác hoặc được thực thi với python thực thi thay vì mở một trình thông dịch mới.

 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.

Như một phần thưởng, cách tiếp cận này cho phép bạn buộc Python sử dụng mô-đun của bạn thay vì mô-đun được cài đặt trên hệ thống.

Cảnh báo! Tôi thực sự không biết điều gì đang xảy ra khi mô-đun hiện tại ở trongegg tệp. Có lẽ nó cũng thất bại.


5
Tôi có thể nhận được một lời giải thích như thế nào điều này hoạt động? Tôi đã gặp một vấn đề tương tự và tôi YÊU một mô-đun python
TRỰC TIẾP

Chạy Win 7 Pro 64x và Python 2.7 Tôi gặp một vài lỗi. 1) Tôi đã phải thêm kiểm tra vào danh sách nhập khẩu. 2) Giá trị thứ nhất, [0], trong bộ dữ liệu là một chuỗi rỗng. Thứ 2, [1], hiển thị tên tệp. Tôi đoán rằng đầu tiên nên là con đường ... Có ý tưởng nào không?
Adam Lewis

2
Nếu bạn đang cho một thư mục con, sử dụng nó như thế này: os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]) + "/subfolder")Đỗ KHÔNG thêm thư mục con trước abspathvì điều này gây ra lỗi nghiêm trọng.
Maximilian Hils

4
@ Scr4ve thay vào đó, bạn nên sử dụng os.path.join () và bạn có thể cmd_subfoldertrực tiếp thêm trường hợp ( ) vào câu trả lời của tôi. cảm ơn!
sorin

7
đối với tôi realpathđã tạo ra các đường dẫn tuyệt đối, do đó tôi không cần abspath. Cũng os.path.dirnamecó thể được sử dụng thay vì phân chia, làm cho việc lập chỉ mục [0]trở nên lỗi thời. Dòng sau đó sẽ là:os.path.realpath(os.path.dirname(inspect.getfile(inspect.currentframe())))
ted

328

Hãy chắc chắn rằng dirBar có __init__.pytệp - điều này tạo một thư mục vào gói Python.


204
Lưu ý rằng tập tin này có thể hoàn toàn trống rỗng.
Harley Holcombe

47
Nếu thư mục cha dirBar không phải là ở sys.pathđó sự hiện diện của __init__.pytrong dirBarthư mục không giúp gì nhiều.
jfs

7
-1, thêm __init.py__sẽ chỉ hoạt động khi thư mục đã có trong sys.path và trong trường hợp của tôi thì không. Giải pháp bằng "sorin" (được chấp nhận) luôn hoạt động.
Czarek Tomczak

12
"khi thư mục đã có trong sys.path". Trong khi hoàn toàn đúng, làm thế nào chúng ta có thể đoán rằng thư mục không có trong sys.pathcâu hỏi? Có lẽ có một cái gì đó bị bỏ qua mà chúng ta không nhìn thấy hoặc biết về?
S.Lott

4
Đây là bởi NO có nghĩa là câu trả lời cho câu hỏi: có hay không tệp khởi tạo ở đó, điều này không làm cho python nhìn vào các thư mục con. Làm thế nào mà nó nhận được hàng trăm upvote?
gents

261

Bạn cũng có thể thêm thư mục con vào đường dẫn Python để nó nhập dưới dạng tập lệnh thông thường.

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

6
Có vẻ như câu trả lời của bạn không hoạt động với các đường dẫn tương đối, xem stackoverflow.com/questions/279237/NH
bogdan

24
Điều này không hoạt động với các đường dẫn tương đối - bạn chỉ cần hiểu rằng một đường dẫn tương đối sẽ phụ thuộc vào thư mục bạn chạy từ đâu, điều này làm cho đây là một giải pháp kém cho bất cứ điều gì khác ngoài việc hack nhanh.
tộc

12
Bạn có thể làm một cái gì đó nhưsys.path.append(os.path.dirname(__file__) + "/relative/path/to/module")
Falko

hoặcsys.path.append(__name__ if __name__ != '__main__' else __loader__.fullname)
vim

1
Cân nhắc sử dụng sys.path.insert(0, <path to dirFoo>)vì nó sẽ tải mô-đun này trước các mô-đun cùng tên được lưu trữ ở nơi khác.
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
Tôi thích điều này bởi vì bạn có thể linh hoạt để đi lên một thư mục.
Charles L.

21
Bạn nên sử dụng os.path.join()thay vì tham gia bởi '/', điều này sẽ phá vỡ trong các cửa sổ (khập khiễng).
0xc0de

18
Điều này không đáng tin cậy. Nó phụ thuộc vào bất cứ thư mục làm việc hiện tại là gì, không phải trên thư mục mà tập lệnh sống.
jamesdlin

Có thể chỉ muốn thêm nếu đường dẫn chưa có trong đường dẫn. lib_path = os.path.abspath ('../ Hàm') nếu lib_path không có trong sys.path: sys.path.append (lib_path)
Brent

để trả lời @jamesdlin kết hợp một vài câu trả lời: còn gì os.path.abspath(os.path.join(__file__,'..','lib'))?
Matthew Davis

107

Chỉ cần làm những việc đơn giản để nhập tệp .py từ một thư mục khác.

Giả sử bạn có một thư mục như:

lib/abc.py

Sau đó, chỉ cần giữ một tập tin trống trong thư mục lib như được đặt tên

__init__.py

Và sau đó sử dụng

from lib.abc import <Your Module name>

Giữ __init__.pytệp trong mọi thư mục phân cấp của mô-đun nhập.


79

Nếu bạn cấu trúc dự án của bạn theo cách này:

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

Sau đó, từ Foo.py bạn sẽ có thể làm:

import dirFoo.Foo

Hoặc là:

from dirFoo.Foo import FooObject

Theo nhận xét của Tom, điều này không yêu cầu srcthư mục có thể truy cập được thông qua site_packageshoặc đường dẫn tìm kiếm của bạn. Ngoài ra, như ông đề cập, __init__.pyđược nhập ngầm khi bạn nhập một mô-đun trong gói / thư mục đó. Thông thường __init__.pychỉ đơn giản là một tập tin trống.


Cũng đề cập rằng init .py được nhập khi mô-đun đầu tiên bên trong gói đó được nhập. Ngoài ra, ví dụ của bạn sẽ chỉ hoạt động nếu src nằm trong site_packages (hoặc trong đường dẫn tìm kiếm)
Tom Leys

3
Đây là giải pháp đơn giản nhất mà tôi đang tìm kiếm. Nếu tệp cần nhập chắc chắn nằm trong một trong các thư mục con, giải pháp này là một viên ngọc.
Deepak GM

Tôi đã thử điều tương tự và thất bại. Tôi không biết tại sao. ImportError: Không có mô-đun nào có tên customMath
Ming Li

9
Tại sao ai đó muốn nhập Foo từ trong chính Foo.py. Tôi đoán là từ Bar.py.
bhaskarc

from dirFoo import Foođể nói Foo.bla(). Nếu sử dụng import dirFoo.Foongười ta nên sử dụng dirFoo.Foo.bla()- khá xấu xí ngay cả khi không có vỏ lạc đà.
Cees Timmerman

45

Phương pháp đơn giản nhất là sử dụng sys.path.append ().

Tuy nhiên, bạn cũng có thể quan tâm đến mô-đun imp . Nó cung cấp quyền truy cập vào các chức năng nhập nội bộ.

# 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 

Điều này có thể được sử dụng để tải mô-đun một cách linh hoạt khi bạn không biết tên của mô-đun.

Trước đây tôi đã sử dụng điều này để tạo giao diện loại plugin cho một ứng dụng, trong đó người dùng sẽ viết một tập lệnh với các chức năng cụ thể của ứng dụng và chỉ cần thả tập lệnh vào một thư mục cụ thể.

Ngoài ra, các chức năng này có thể hữu ích:

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

Lưu ý rằng trong tài liệu imp.load_source và imp.load_compiled được liệt kê là lỗi thời. Thay vào đó, imp.find_module và imp.load_module được khuyên dùng.
amellyas

@amicitas, bạn có thể vui lòng cung cấp bất kỳ tài liệu tham khảo nào cho điều đó không (tôi cần nó và tôi đang sử dụng python 2.6. Tôi biết 2.7 tài liệu nói gì về những điều này, nhưng không thể tìm thấy bất kỳ tài liệu tham khảo nào về 2.6)
0xc0de

@ 0xc0de Bạn có thể tìm thấy câu lệnh đó trong các tài liệu cho mô-đun imp cho cả python 2.7.3python 2.6.7 . Có vẻ như các chức năng đó thậm chí không có trong tài liệu cho python 3.2.
amellyas

1
Để nhập tệp nguồn như thế này trong python 3.3, hãy xem Nhập tệp nguồn python abitrary. (Python 3.3+) - Tràn ngăn xếp . Cảm ơn, folks cho lời khuyên ở đây.
nealmcb


23

Cách dễ nhất mà không có bất kỳ sửa đổi nào đối với tập lệnh của bạn là đặt biến môi trường PYTHONPATH. Vì sys.path được khởi tạo từ các vị trí này:

  1. Thư mục chứa tập lệnh đầu vào (hoặc thư mục hiện tại).
  2. PYTHONPATH (danh sách các tên thư mục, có cùng cú pháp với biến shell PATH).
  3. Mặc định phụ thuộc cài đặt.

Chỉ cần chạy:

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

Bạn sys.path sẽ chứa đường dẫn trên, như hiển thị bên dưới:

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

Theo tôi, lựa chọn tốt nhất là đặt __ init __.py vào thư mục và gọi tệp bằng

from dirBar.Bar import *

Không nên sử dụng sys.path.append () vì có thể có lỗi xảy ra nếu bạn sử dụng cùng tên tệp với gói python hiện có. Tôi đã không kiểm tra điều đó nhưng điều đó sẽ mơ hồ.


lạ mà from dirBar.Bar import *hoạt động, nhưng không from dirBar.Bar import Bar. bạn có biết tại sao * hoạt động không? Điều gì xảy ra nếu tôi có nhiều tệp trong dirBar / và chỉ muốn lấy một vài trong số chúng (sử dụng một phương thức như cách bạn đã đăng ở đây)?
người kiểm tra

2
@tester: Sử dụng from dirBar import Bar.
tộc

@tester đó là vì fromnguồn chỉ ra nguồn và mọi thứ sau đó importlà thứ cần lấy từ nguồn đó. from dirBar.Bar import Barcó nghĩa là "Từ nguồn, nhập chính nguồn", không có nghĩa. các *mặc dù có nghĩa là "cho tôi tất cả mọi thứ từ nguồn"
FuriousFolder

11

Cách nhanh và bẩn cho người dùng Linux

Nếu bạn chỉ mày mò và không quan tâm đến các vấn đề triển khai, bạn có thể sử dụng một liên kết tượng trưng (giả sử hệ thống tệp của bạn hỗ trợ nó) để hiển thị mô-đun hoặc gói trực tiếp trong thư mục của mô-đun yêu cầu.

ln -s (path)/module_name.py

hoặc là

ln -s (path)/package_name

Lưu ý: "mô-đun" là bất kỳ tệp nào có phần mở rộng .py và "gói" là bất kỳ thư mục nào chứa tệp __init__.py(có thể là tệp trống). Từ quan điểm sử dụng, các mô-đun và gói giống hệt nhau - cả hai đều phơi bày "định nghĩa và câu lệnh" chứa theo yêu cầu thông qua importlệnh.

Xem: http://docs.python.org/2/tutorial/modules.html


10
from .dirBar import Bar

thay vì:

from dirBar import Bar

chỉ trong trường hợp có thể có một dirBar khác được cài đặt và gây nhầm lẫn cho trình đọc foo.py.


2
Tôi đã không thể làm điều này trên windows. Đây có phải trên Linux không?
Gabriel

1
Nó sẽ hoạt động từ một tập lệnh nhập Foo. tức là: main.txt nhập dirFoo.Foo. Nếu bạn đang cố chạy Foo.py dưới dạng tập lệnh, nó sẽ thất bại. Xem stackoverflow.com/questions/72852/iêu
jgomo3

9

Trong trường hợp này để nhập Bar.py vào Foo.py, trước tiên tôi muốn biến các thư mục này thành các gói Python như vậy:

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

Sau đó, tôi sẽ làm như thế này trong Foo.py:

from .dirBar import Bar

Nếu tôi muốn không gian tên trông giống như Bar. bất cứ điều gì , hoặc

from . import dirBar

Nếu tôi muốn không gian tên dirBar.Bar. bất cứ điều gì . Trường hợp thứ hai này rất hữu ích nếu bạn có nhiều mô-đun trong gói dirBar.


7

Thêm tệp __init__.py :

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

Sau đó thêm mã này vào đầu Foo.py:

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

5
Nếu dirBarđã là một gói Python (bởi sự tồn tại của dirBar/__init__.py), thì không cần phải thêm dirBarvào sys.path, phải không? Các tuyên bố import Bartừ Foo.pynên đủ.
Santa

5

Ví dụ sys.path tương đối:

# /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

Dựa trên câu trả lời này .


5

Vâng, như bạn đã đề cập, thông thường bạn muốn có quyền truy cập vào một thư mục với các mô-đun của bạn liên quan đến nơi tập lệnh chính của bạn được chạy, vì vậy bạn chỉ cần nhập chúng.

Giải pháp:

Tôi có tập lệnh trong D:/Books/MyBooks.pyvà một số mô-đun (như oldies.py). Tôi cần nhập từ thư mục con D:/Books/includes:

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

Đặt một print('done')trong oldies.py, để bạn xác minh mọi thứ sẽ ổn. Cách này luôn hoạt động vì theo định nghĩa Python được sys.pathkhởi tạo khi khởi động chương trình, mục đầu tiên của danh sách này,path[0] , là thư mục chứa tập lệnh được sử dụng để gọi trình thông dịch Python.

Nếu thư mục tập lệnh không khả dụng (ví dụ: nếu trình thông dịch được gọi tương tác hoặc nếu tập lệnh được đọc từ đầu vào tiêu chuẩn), thì đó path[0]là chuỗi trống, điều hướng Python đến các mô-đun tìm kiếm trong thư mục hiện tại trước tiên. Lưu ý rằng thư mục script được chèn trước khi các mục được chèn là kết quả của PYTHONPATH.


1
Tôi đã phải sử dụng một dấu gạch chéo về phía trước thay vì hai dấu gạch chéo ngược (nghĩa là site.addsitedir(sys.path[0]+'/includes')) trong chương trình Python đơn giản đầu tiên của tôi break_time.py: https://github.com/ltfschoen/PythonTest . Tôi sử dụng hệ thống: MacOS v10.11.5, Python 2.7.12, IDLE IDE 2.7.12, Tk 8.5.9
Luke Schoen

4

Đơn giản là bạn có thể sử dụng: from Desktop.filename import something

Thí dụ:

cho rằng tập tin là tên test.pytrong thư mục Users/user/Desktop, và sẽ nhập mọi thứ.

mật mã:

from Desktop.test import *

Nhưng hãy chắc chắn rằng bạn tạo một tệp trống có tên " __init__.py" trong thư mục đó


1
nhập khẩu sao được khuyến cáo chống lại. xem: stackoverflow.com/questions/2386714/why-is-import-bad
axolotl

Tôi biết đó là lý do tại sao lần đầu tiên tôi viết import somethingsau đó tôi đã nói để làm cho nó dễ dàng hơn * về cơ bản nó không tốt cho ram và nếu 2 hàm có cùng tên thì nó sẽ mã hóa mã của bạn
0x1996

3

Một giải pháp khác là cài đặt gói py-request và sau đó sử dụng cách sau trongFoo.py

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

URL thực sự có vẻ là pypi.org/project/require.py và lưu ý rằng nó cần phải được cài đặt qua Pip.
Flash Sheridan

1
@FlashSheridan Không, đó là một dự án khác. Tôi đã xóa py-request vì tôi chắc chắn không có ai sử dụng nó, mặc dù vậy tôi không nghĩ đến bài đăng này. Nếu bạn vẫn cần một require()chức năng, bạn có thể xem dự án Node.py của tôi: github.com/nodepy/nodepy
Niklas R

2

Đây là một cách để nhập tệp từ một cấp trên, sử dụng đường dẫn tương đối.

Về cơ bản, chỉ cần di chuyển thư mục làm việc lên một cấp độ (hoặc bất kỳ vị trí tương đối nào), thêm nó vào đường dẫn của bạn, sau đó di chuyển thư mục làm việc trở lại nơi nó bắt đầu.

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

1
tôi không hiểu bạn logic ở đây. nó quá phức tạp
transilvlad

0

Tôi không có kinh nghiệm về trăn, vì vậy nếu có bất kỳ sai trong lời nói của tôi, chỉ cần nói với tôi. Nếu hệ thống phân cấp tệp của bạn được sắp xếp như thế này:

project\
    module_1.py 
    module_2.py

module_1.pyđịnh nghĩa một hàm được gọi là func_1(), module_2.py :

from module_1 import func_1

def func_2():
    func_1()

if __name__ == '__main__':
    func_2()

và bạn chạy python module_2.pytrong cmd, nó sẽ chạy những gì func_1()định nghĩa. Đó thường là cách chúng ta nhập các tệp phân cấp giống nhau. Nhưng khi bạn viết from .module_1 import func_1vào module_2.py, trình thông dịch python sẽ nói No module named '__main__.module_1'; '__main__' is not a package. Vì vậy, để khắc phục điều này, chúng tôi chỉ cần giữ thay đổi mà chúng tôi vừa thực hiện và di chuyển cả hai mô-đun sang một gói và tạo một mô-đun thứ ba như một người gọi để chạy module_2.py.

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

chính :

from package_1.module_2 import func_2

def func_3():
    func_2()

if __name__ == '__main__':
    func_3()

Nhưng lý do chúng tôi thêm vào .trước đó là nếu chúng tôi không làm điều đó và chạy , thông dịch viên python sẽ nói , đó là một chút khó khăn, ở ngay bên cạnh . Bây giờ tôi cho phép trong việc phải làm một cái gì đó:module_1module_2.pymain.pyNo module named 'module_1'module_1.pymodule_2.pyfunc_1()module_1.py

def func_1():
    print(__name__)

rằng __name__hồ sơ người gọi func_1. Bây giờ chúng tôi giữ .trước module_1, chạy main.py, nó sẽ inpackage_1.module_1 , không module_1. Nó chỉ ra rằng người gọi func_1()có cùng thứ bậc với main.py, .hàm ý đó module_1có cùng thứ bậc với module_2.pychính nó. Vì vậy, nếu không có dấu chấm, main.pysẽ nhận ra module_1ở cùng một hệ thống phân cấp như chính nó, nó có thể nhận ra package_1, nhưng không phải là "dưới" nó.

Bây giờ hãy làm cho nó một chút phức tạp. Bạn có một config.inivà một mô-đun xác định một chức năng để đọc nó ở cùng một hệ thống phân cấp như 'main.py'.

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

Và vì một số lý do không thể tránh khỏi, bạn phải gọi nó bằng module_2.py, vì vậy nó phải nhập từ phân cấp cao hơn. module_2.py :

 import ..config
 pass

Hai dấu chấm có nghĩa là nhập từ phân cấp trên (ba dấu chấm truy cập trên so với trên, v.v.). Bây giờ chúng tôi chạy main.py, thông dịch viên sẽ nói : ValueError:attempted relative import beyond top-level package. "Gói cấp cao nhất" ở đây là main.py. Chỉ vì config.pybên cạnhmain.py , chúng ở cùng một hệ thống phân cấp, config.pykhông phải là "dưới" main.py, hoặc nó không được "dẫn dắt" bởi main.pyvì vậy nó vượt xa main.py. Để khắc phục điều này, cách đơn giản nhất là:

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

Tôi nghĩ rằng đó là trùng khớp với nguyên tắc sắp xếp phân cấp tệp dự án, bạn nên sắp xếp các mô-đun với chức năng khác nhau trong các thư mục khác nhau và chỉ để lại một người gọi hàng đầu ở bên ngoài và bạn có thể nhập bất cứ khi nào bạn muốn.


-5

Điều này cũng hoạt động, và đơn giản hơn nhiều so với bất cứ điều gì với sysmô-đun:

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

1
Nếu OP định mã hóa một đường dẫn, họ có thể chỉ cần chèn đường dẫn đó vào PYTHONPATH. Tôi nghĩ rằng vấn đề là làm theo cách không mã hóa một đường dẫn vì nó sẽ phá vỡ bất cứ nơi nào khác.
Matthew

-15

Gọi cho tôi quá thận trọng, nhưng tôi muốn làm cho tôi dễ mang theo hơn vì không an toàn khi cho rằng các tệp sẽ luôn ở cùng một vị trí trên mọi máy tính. Cá nhân tôi có mã tra cứu đường dẫn tập tin đầu tiên. Tôi sử dụng Linux vì vậy tôi sẽ trông như thế này:

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!")

Đó là điều tất nhiên trừ khi bạn có kế hoạch gói những thứ này lại với nhau. Nhưng nếu đó là trường hợp bạn không thực sự cần hai tệp riêng biệt.


11
Siêu kém hiệu quả!
0xc0de

1
Các tệp sẽ luôn ở cùng một vị trí trên mọi máy tính, được cung cấp một đường dẫn tương đối.
Sagar Hatekar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.