2013-08-05 53 views
5

Tôi đang gặp một số khó khăn trong việc tìm ra cách thực hiện nhập khẩu tương đối bằng Python. Tôi hiện đang làm việc cho dự án lớn đầu tiên của mình nên tôi muốn làm điều đó ngay bằng cách sử dụng các bài kiểm tra đơn vị. Tuy nhiên, tôi gặp sự cố với cấu trúc tệp và nhập tương đối của mình.Sự nhầm lẫn nhập khẩu tương đối bằng Python

Dưới đây là cấu trúc hiện tại của tôi:

App/ 
    __init__.py 
    src/ 
    __init__.py 
    person.py 
    tests/ 
    __init__.py 
    person_tests.py 

Những gì tôi muốn làm là có thể nhập person.py vào person_tests.py cho các bài kiểm tra đơn vị. Tôi đã cố gắng những điều sau đây:

from . import person 
from .. import person 
from .App.src import person 
from ..App.src import person 
from ..src.person import * 
from ..src import person 
from .src import person 

Mỗi một trong những trên throws hoặc là một lỗi cú pháp hoặc

ValueError: Attempted relative import in non-package 

Có thể ai đó xin vui lòng làm rõ điều này cho tôi?

Chỉnh sửa: Phiên bản Python là 2.7. Chỉnh sửa: Tôi muốn có thể sử dụng tính năng này bằng cách nói là không hay hoặc mũi.

+1

Tôi cho rằng nhập khẩu tuyệt đối là cách được ưu tiên trong hầu hết các trường hợp. [Một số đọc] (http://www.python.org/dev/peps/pep-0328/#rationale-for-absolute-imports) (đừng bỏ lỡ phần sau phần đó về nhập khẩu tương đối). – keyser

+0

Bạn có thể thêm tệp (có thể) trống "' __init __. Py' "trong thư mục" 'App'" để làm cho nó thành gói –

+0

Rất tiếc. Tôi quên đề cập đến rằng tôi có một tập tin '__init __. Py' trong thư mục App. Đang cập nhật câu hỏi. – firstofth300

Trả lời

-1

bạn có thể thêm nó vào sys.path.

import sys 
sys.path.append("../src") 
import person 
+1

Bạn có thể xây dựng thêm một chút không? – horchler

+0

Bằng cách appelling một thư mục vào đường dẫn Python, bạn đang nói rằng có một thư mục mới để tìm kiếm các tập tin/mô-đun –

+0

Điều này sẽ làm việc, nhưng đó là một ý tưởng tồi. Bạn có xu hướng kết thúc với cùng một mô-đun được nhập hai lần dưới các tên khác nhau (có nghĩa là hai bản sao riêng biệt của mỗi tên chung, v.v.). [PEP 328] (http://www.python.org/dev/peps/pep-0328/) giải thích lý do. Nếu bạn phải làm điều này, hãy thêm cấp cao nhất của gói vào đường dẫn và nhập tuyệt đối nó vào. – abarnert

4

Tôi đoán (và tôi sẽ xóa điều này nếu tôi sai) là bạn đang cố gắng sử dụng person_tests.py làm tập lệnh cấp cao nhất, thay vì làm mô-đun bên trong gói, bằng cách thực hiện như sau:

$ cd App/tests 
$ python person_tests.py 

Trong trường hợp đó, person_tests không kết thúc như App.tests.person_tests, nhưng khi chỉ __main__ (hoặc, với các biến thể nhỏ, như các cấp cao nhất person_tests, trong đó có các vấn đề cơ bản giống nhau). Vì vậy, .. không tham chiếu đến App và do đó không có cách nào để truy cập vào person dưới dạng lượt nhập tương đối.

Nói chung, không có gì trên PYTHONPATH, bao gồm ., nên ở giữa bất kỳ thư mục gói nào hoặc mọi thứ sẽ bị hỏng.

Câu trả lời đúng là không làm điều đó. Làm một cái gì đó như thế này:

$ python -m App.tests.person_tests 

Hoặc viết một cấp cao nhất (bên ngoài gói) kịch bản nhập khẩu các mô-đun, và chạy mà kịch bản cấp cao nhất.

+0

Vì vậy, tôi đoán bạn đang đề xuất rằng tôi viết của riêng tôi pythonic unittest Á hậu. – firstofth300

+0

@DaBungalow: Không hề. Hoặc là sử dụng một runner không đạt tiêu chuẩn, hoặc giữ cho mọi thứ đơn giản và chạy thử nghiệm của bạn bằng tay, nhưng làm như vậy theo cách hoạt động thay vì cách không hoạt động. Tôi cho rằng một kịch bản wrapper tầm thường xung quanh cách mà các tác phẩm có thể được tính là một Á hậu không tùy chỉnh, nhưng thực sự, chúng ta đang nói về một lớp lót ở đó… – abarnert

+0

OK. Điều đó chỉ nhắc tôi rằng tôi đã để lại một thứ rất quan trọng. Tôi muốn có thể sử dụng unittest hoặc mũi. – firstofth300

1

Cũng như abarnert nói, bạn không thể thực thi kịch bản như chính cho việc nhập khẩu tương đối dựa trên tên hiện tại của kịch bản. Được trích dẫn từ tài liệu:

Lưu ý rằng cả nhập khẩu tương đối rõ ràng và tiềm ẩn đều dựa trên tên của mô-đun hiện tại. Vì tên của mô-đun chính là luôn luôn là "__main__", nên các mô-đun được sử dụng làm mô-đun chính của ứng dụng Python phải luôn sử dụng nhập khẩu tuyệt đối.

. đại diện cho gói hiện tại và .. đại diện cho gói chính. Vì vậy, một số tuyên bố nhập của bạn là sai.

from . import person # wrong for no person module in package tests 
from .. import person # wrong for no person module in package app 
from .App.src import person # wrong for no app package in package tests 
from ..App.src import person # wrong for no app package in package app 
from ..src.person import * # right 
from ..src import person # right 
from .src import person # wrong 

Bạn có thể tham chiếu PEP328 cho tiêu chuẩn nhập tương đối.