2012-05-08 26 views
9

Giả sử tôi có một gói có chứa các module:module Python với tên giống hệt nhau (ví dụ, tái sử dụng tên mô-đun tiêu chuẩn trong gói)

SWS/ 
    __init.py__ 
    foo.py 
    bar.py 
    time.py 

và các module cần phải tham khảo chức năng chứa trong nhau. Có vẻ như tôi gặp sự cố với mô-đun time.py của mình vì có một mô-đun chuẩn đi cùng tên.

Ví dụ, trong trường hợp đó mô-đun foo.py của tôi đòi hỏi cả hai SWS.time và tiêu chuẩn python time module của tôi, tôi chạy vào rắc rối kể từ khi dịch viên sẽ nhìn vào bên trong các gói và tìm time.py module của tôi trước khi nó đi qua các time mô-đun tiêu chuẩn .

Có cách nào xung quanh vấn đề này không? Đây có phải là tình huống không và không nên sử dụng lại tên mô-đun?

Bất kỳ giải pháp và ý kiến ​​nào về triết lý gói đều hữu ích ở đây.

+2

Tôi nghĩ rõ ràng là bạn không nên sử dụng lại tên mô-đun python chuẩn. Nó chỉ yêu cầu rắc rối. – Cryptite

+3

Tại sao nó rõ ràng? MikeWyatt

+0

Nhìn vào httplib/httplib2 và urllib/urllib2. Nó làm cho một thế giới xấu xí của thư viện, nhưng đó là thích hợp hơn để đặt tên va chạm và hành vi không xác định. –

Trả lời

10

Việc sử dụng lại tên của các chức năng/lớp/mô-đun/gói chuẩn không bao giờ là ý tưởng hay. Cố gắng tránh nó càng nhiều càng tốt. Tuy nhiên, có cách giải quyết rõ ràng cho tình huống của bạn.

Hành vi bạn thấy, nhập SWS.time thay vì stdlib time, là do ngữ nghĩa của import trong phiên bản python cổ đại (2.x). Để khắc phục sự cố, hãy thêm:

from __future__ import absolute_import 

ở đầu tệp. Điều này sẽ thay đổi ngữ nghĩa của import thành ngữ nghĩa của python3.x, hợp lý hơn nhiều. Trong trường hợp đó, tuyên bố:

import time 

Sẽ chỉ tham chiếu đến mô-đun cấp cao nhất. Vì vậy, thông dịch viên sẽ không xem xét mô-đun SWS.time của bạn khi thực thi việc nhập đó bên trong gói, nhưng nó sẽ chỉ sử dụng thư viện chuẩn.

Nếu một module bên gói của bạn cần phải nhập SWS.time bạn có thể lựa chọn:

  • Sử dụng một rõ ràng nhập khẩu tương đối:

    from . import time 
    
  • Sử dụng nhập khẩu tuyệt đối:

    import SWS.time as time 
    

Vì vậy, foo.py của bạn sẽ là một cái gì đó như:

from __future__ import absolute_import 

import time 

from . import time as SWS_time 
+2

Tôi cho rằng đó không phải là ý tưởng tồi * khi tên mô-đun nằm trong sự hiện diện của không gian tên *, giống như một gói. Đây là tinh thần của PEP328. Xem câu trả lời của tôi dưới đây. – OozeMeister

0

Vâng, thực sự không có cách nào tốt đẹp xung quanh nó. Cố gắng không đặt tên cho các mô-đun của bạn như các gói tiêu chuẩn. Nếu bạn thực sự muốn gọi mô-đun của mình là time, tôi khuyên bạn nên sử dụng _time.py để thay thế. Ngay cả khi có một cách để làm điều đó, nó sẽ làm cho mã của bạn khó đọc và khó hiểu khi nó đến các mô-đun 2 thời gian.

4

Nó phụ thuộc vào những gì phiên bản của Python bạn đang sử dụng. Nếu phiên bản Python được nhắm mục tiêu của bạn là 2.4 hoặc cũ hơn (vào năm 2015, tôi chắc chắn hy vọng không), thì có nó sẽ là thực hành xấu vì không có cách nào (không có hack) để phân biệt hai mô-đun.

Tuy nhiên, trong Python 2.5+, tôi nghĩ rằng việc sử dụng lại tên mô-đun lib chuẩn trong không gian tên gói là hoàn toàn tốt; trên thực tế, đó là the spirit of PEP328.

Khi thư viện của Python mở rộng, ngày càng nhiều mô-đun nội bộ gói hiện đột nhiên ẩn mô-đun thư viện chuẩn. Đó là một vấn đề đặc biệt khó khăn bên trong các gói vì không có cách nào để xác định mô-đun nào có nghĩa là. Để giải quyết sự mơ hồ, nó được đề xuất rằng foo sẽ luôn là một mô-đun hoặc gói có thể truy cập từ sys.path. Đây được gọi là nhập khẩu tuyệt đối.

Cộng đồng python-dev đã chọn nhập khẩu tuyệt đối làm mặc định vì chúng là trường hợp sử dụng phổ biến hơn và vì nhập khẩu tuyệt đối có thể cung cấp tất cả chức năng nhập khẩu tương đối (trong gói) - mặc dù chi phí khó khăn đổi tên các phần của gói cao hơn trong hệ thống phân cấp hoặc khi di chuyển một gói bên trong một gói khác.

Bởi vì điều này thể hiện một sự thay đổi trong ngữ nghĩa, nhập khẩu tuyệt đối sẽ không bắt buộc bằng Python 2.5 và 2.6 thông qua việc sử dụng các from __future__ import absolute_import

SWS.time rõ ràng là không điều tương tự như time và như một độc giả của các mã, tôi mong đợi SWS.time để không chỉ sử dụng time, nhưng để mở rộng nó theo một cách nào đó.

Vì vậy, nếu SWS.foo nhu cầu nhập khẩu SWS.time, sau đó nó phải sử dụng đường dẫn tuyệt đối:

# in SWS.foo 

# I would suggest renaming *within* 
# modules that use SWS.time so that 
# readers of your code aren't confused 
# with which time module you're using 
from SWS import time as sws_time 

Hoặc, nó nên sử dụng một rõ ràng nhập khẩu tương đối như trong câu trả lời Bakuriu của:

# in SWS.foo 

from . import time as sws_time 

Trong trường hợp bạn cần nhập khẩu mô-đun lib chuẩn time trong mô-đun SWS.time, trước tiên bạn sẽ cần nhập tính năng trong tương lai (chỉ dành cho Python 2.5+; Python 3+ thực hiện điều này theo mặc định):

# inside of SWS.time 
from __future__ import absolute_import 

import time 

time.sleep(28800) # time for bed 

Lưu ý:from __future__ import absolute_imports sẽ chỉ ảnh hưởng đến báo cáo nhập khẩu trong module rằng tính năng tương lai được nhập khẩu và sẽ không ảnh hưởng đến bất kỳ thành phần khác (như rằng sẽ bất lợi nếu mô-đun khác phụ thuộc vào nhập khẩu tương đối).

+0

Lưu ý rằng báo giá của bạn từ PEP 8 là ** lỗi thời **. Phiên bản hiện tại của PEP 8 * xác nhận bằng cách sử dụng nhập khẩu tương đối *: Trích dẫn: * nhập khẩu tương đối rõ ràng là một thay thế có thể chấp nhận được đối với nhập khẩu tuyệt đối, đặc biệt khi xử lý các bố cục gói phức tạp khi sử dụng nhập khẩu tuyệt đối sẽ không cần thiết * – Bakuriu

+1

@Bakuriu, darn. Tôi không biết rằng PEP có thể thay đổi như thế. Tôi sẽ cập nhật câu trả lời của mình. Tuy nhiên, tôi vẫn sẽ duy trì lập luận của tôi rằng có một mô-đun được đóng gói có tên giống như một mô-đun stdlib cấp cao nhất không chỉ cho phép mà còn được khuyến khích. – OozeMeister

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