2011-12-06 27 views
5

Tôi có mã python trong một thư mục có tên là "project", vì vậy các tệp mã của tôi nằm trong project/*. Py. Tôi muốn có các mô-đun con trong đó, ví dụ:tổ chức mô-đun pythonic - cách tham chiếu đến các tệp trong thư mục gốc?

project/code.py # where code lives 
project/mymodule1 # where more code lives 
project/mymodule2 

mỗi thư mục module có riêng init tập tin py của nó, ví dụ

project/mymodule1/__init__.py 

giả sử tôi có tệp "test.py" trong mymodule1 (project/mymodule1/test.py) và tôi muốn tham khảo một điều gì đó từ "mã", ví dụ: nhập hàm "myfunc"

== project/mymodule1/test.py == 
from code import myfunc 

vấn đề là "mã" sẽ không được tìm thấy trừ khi người dùng đã đặt thư mục "project /" trong PYTHONPATH của họ. Có cách nào để tránh điều này và sử dụng một số loại "đường dẫn tương đối" để nhập myfunc, ví dụ:

from ../code import myfunc 

về cơ bản, tôi không muốn ép buộc người dùng mã thay đổi PYTHONPATH trừ khi tôi có thể làm điều đó theo chương trình cho chúng từ bên trong tập lệnh của tôi. Tôi muốn nó làm việc ra khỏi hộp.

Làm cách nào để thực hiện điều này? hoặc là giải pháp tốt: thay đổi PYTHONPATH theo lập trình, hoặc lý tưởng hơn, tham chiếu đến "mã" bằng cách sử dụng một loại nhập tương đối, vì mặc dù tôi không biết "project/code.py" ở đâu trên máy tính của người dùng, tôi biết nó liên quan đến "myfunc".

EDIT: Ai đó có thể vui lòng hiển thị ví dụ thích hợp về nhập gói nội bộ không? Tôi đã thử, từ "mymodule1" để làm:

from .. import foo 

trong đó "foo" nằm trong code.py nhưng nó không hoạt động. Tôi có init py trong mymodule1, vì vậy:

project/code.py 
project/mymodule1/__init__.py 
project/mymodule1/module1_code.py 

nơi module1_code.py cố gắng nhập foo, một chức năng được xác định trong "code.py". EDIT: Sự nhầm lẫn chính tôi vẫn có là ngay cả sau khi chấp nhận ví dụ được đưa ra để trả lời thông báo của tôi, hiển thị phân cấp dự án/sub1/test, bạn vẫn không thể "cd" vào sub1 và làm "python test.py "và có nó hoạt động. Người dùng phải nằm trong thư mục chứa "project" và làm "import project.sub1.test". Tôi muốn điều này làm việc bất kể thư mục người dùng đang ở. Người dùng trong trường hợp này phải thực thi tệp "test.py", nằm trong dự án/sub1 /. Vì vậy, các trường hợp thử nghiệm là:

$ cd project/sub1 
$ python test.py 

trong đó sản lượng các lỗi:

ValueError: Attempted relative import in non-package 

cách này có thể được cố định?

cảm ơn.

+0

'code.py' cũng có nhập' mymodule1/test.py' không? Nếu có, bạn sẽ muốn xem xét sắp xếp lại mã của mình. Nên tránh nhập khẩu thông tư nếu có thể. – Wilduck

Trả lời

3

Điều này có thể có trong Python 2.5 trở lên. Xem tài liệu trên Intra-Package References.

Một vài điều cần lưu ý:

Nếu bạn có ý định cho người dùng của bạn cài đặt gói của bạn ở đâu đó, ví dụ như sử dụng distutils hoặc setuptools, sau đó project sẽ có khả năng đã có trong đường dẫn tìm kiếm, và bạn có thể thay đổi nhập tương đối thành from project.code import ... hoặc tương tự. Trong trường hợp người dùng của bạn đang cài đặt gói của bạn vào thư mục không chuẩn (ví dụ: thư mục chính của họ, một nơi nào đó không nằm trong số sys.path, v.v.), ý kiến ​​của tôi là nó dẫn đến ít nhầm lẫn hơn để hướng dẫn người dùng để sửa đổi PYTHONPATH thay vì thay đổi theo chương trình sys.path. Trong trường hợp bạn không có ý định cài đặt mã của mình - ví dụ, họ chỉ đơn giản là sửa mã nguồn, cd'ing vào thư mục mẹ của project và chạy một tập lệnh - sau đó là nội tham chiếu -package và nhập khẩu tương đối có thể sẽ hoạt động tốt.

EDIT: theo yêu cầu, đây là một ví dụ:

Giả sử bố trí gói như sau:

project/ 
    __init__.py (empty) 
    code.py 
    sub1/ 
     __init__.py (empty) 
     test.py 

Bây giờ, nội dung của project/code.py là:

# code.py (module that resides in main "project" package) 

def foo(): 
    print "this is code.foo" 

Và, nội dung của project/sub1/test.py là:

# test.py (module that resides in "sub1" subpackage of main "project" package) 

from ..code import foo 
foo() 

Vì vậy, test.py nhập tên foo từ đường dẫn tương đối ..code, trong đó sử dụng tài liệu tham khảo nội bộ gói để có được chúng trở lại các module code.py trong mẹ (đó là phần ..) của gói sub1.test nơi chúng tôi đang thực thi từ.

Để kiểm tra điều này:

shell$ (cd to directory where "project" package is located) 
shell$ python 
Python 2.6.1 (r261:67515, Aug 2 2010, 20:10:18) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import project.sub1.test 
this is code.foo 

Lưu ý rằng các dấu chấm đôi trong cú pháp from .. import X chỉ đơn thuần giúp bạn để gói phụ huynh, nhưng bạn có thể xác định những module trong gói đó.

Nói cách khác, from .. import X trong trường hợp này là tương đương với from project import X, và do đó X phải thể là một mô-đun trong project hoặc một lớp/chức năng/tên trong project/__init__.py.

Do đó, from ..code import X tương đương với from project.code import X.

+0

Có thể ai đó vui lòng hiển thị ví dụ thích hợp về nhập gói nội bộ không? Tôi đã thử, từ "mymodule1" để làm: từ .. import foo, trong đó "foo" nằm trong code.py nhưng nó không hoạt động. Tôi có __init__.py trong mymodule1 – user248237dfsf

+0

@ user248237: xem câu trả lời đã sửa đổi của tôi bao gồm ví dụ. Sự khác biệt chính là 'from .. import foo' tương đương với việc tìm kiếm' project/__ init __. Py', không phải 'code.py'. – bjlaub

+1

những gì tôi không nhận được là lý do tại sao nếu bạn cd vào "sub1" và làm: python test.py, bạn nhận được lỗi "ValueError: Cố gắng nhập khẩu tương đối không gói" – user248237dfsf

1

cách tốt nhất để tránh điều này là giữ tất cả mã của bạn trong thư mục src hoặc đặt tên tốt hơn trong dự án của bạn, ví dụ:myproject và giữ một __init__.py ở đó, vì vậy bạn có thể làm điều này

from myproject import code 

nên cấu trúc thư mục của bạn sẽ là

project 
    main.py 
    myproject 
     __init__.py 
     code.py 
     module1 
     module2 

main.py hoặc bất cứ tên nào bạn cung cấp cho nó không nên có nhiều mã, nó nên được yêu cầu mô-đun từ myproject và chạy ví dụ

from myproject import myapp 
myapp.run() 

xem tốt article về cách sắp xếp dự án python của bạn.

+0

mà không giải quyết được vấn đề - làm thế nào mã của module1 có thể gọi những thứ được định nghĩa ngược dòng không? trong thư mục gốc? – user248237dfsf

+0

myproject sẽ nằm trong đường dẫn python và mọi mô-đun có thể nhập bất kỳ mô-đun nào, ví dụ: 'từ myproject.module1 import xxx' –

+0

1) Tôi nghĩ bạn có nghĩa là 'project' sẽ ở trong PYTHONPATH, không phải 'myproject', và (2) Không có nó sẽ không nếu quá trình được bắt đầu sử dụng 'python myproject/code.py" Câu hỏi của anh ấy vẫn chưa được giải quyết, IMHO –

Các vấn đề liên quan