Làm cách nào để tôi viết các tập tin __init__ phút


187

Gói của tôi có cấu trúc như sau:

mobilescouter/
    __init__.py #1
    mapper/
        __init__.py  #2
        lxml/
            __init__.py #3
            vehiclemapper.py
            vehiclefeaturemapper.py
            vehiclefeaturesetmapper.py
        ...
        basemapper.py
   vehicle/
        __init__.py #4
        vehicle.py
        vehiclefeature.py
        vehiclefeaturemapper.py
   ...

Tôi không chắc làm thế nào các __init__.pytập tin nên được viết chính xác.
Hình __init__.py #1như:

__all__ = ['mapper', 'vehicle']
import mapper
import vehicle

Nhưng ví dụ __init__.py #2như thế nào? Của tôi là:

__all__ = ['basemapper', 'lxml']
from basemaper import *
import lxml

Khi nào nên __all__sử dụng?


2
Tuy nhiên, hãy lưu ý rằng việc sử dụng nhập * trong mã nói chung là thực tiễn rất xấu và nên tránh nếu có thể. Có rất ít trường hợp sử dụng tốt cho việc này, nhưng chúng thực sự rất hiếm.
Mayou36

PSA: nếu bạn muốn tìm hiểu cách viết các gói không gian tên tốt (loại gói mới), hãy xem gói ví dụ này: github.com/pypa/sample-namespace-packages
Kyle

Câu trả lời:


145

__all__là rất tốt - nó giúp hướng dẫn nhập các câu lệnh mà không cần tự động nhập các mô-đun http://docs.python.org/tutorial/modules.html#importing-from-a-package

sử dụng __all__import *là dư thừa, chỉ __all__cần thiết

Tôi nghĩ rằng một trong những lý do mạnh mẽ nhất để sử dụng import *trong một __init__.pygói nhập khẩu là có thể cấu trúc lại một tập lệnh đã phát triển thành nhiều tập lệnh mà không phá vỡ một ứng dụng hiện có. Nhưng nếu bạn đang thiết kế một gói từ đầu. Tôi nghĩ tốt nhất là để __init__.pytrống các tập tin.

ví dụ:

foo.py - contains classes related to foo such as fooFactory, tallFoo, shortFoo

sau đó ứng dụng phát triển và bây giờ là toàn bộ thư mục

foo/
    __init__.py
    foofactories.py
    tallFoos.py
    shortfoos.py
    mediumfoos.py
    santaslittlehelperfoo.py
    superawsomefoo.py
    anotherfoo.py

sau đó tập lệnh init có thể nói

__all__ = ['foofactories', 'tallFoos', 'shortfoos', 'medumfoos',
           'santaslittlehelperfoo', 'superawsomefoo', 'anotherfoo']
# deprecated to keep older scripts who import this from breaking
from foo.foofactories import fooFactory
from foo.tallfoos import tallFoo
from foo.shortfoos import shortFoo

để một kịch bản được viết để làm như sau không bị phá vỡ trong quá trình thay đổi:

from foo import fooFactory, tallFoo, shortFoo

3
Tôi đã rất bối rối về ' tất cả ' và nhập theo dòng. Ví dụ của bạn rất sáng sủa.
Junchen

2
Tôi bối rối bởi " __all__import *là dư thừa", __all__được sử dụng bởi người tiêu dùng mô-đun và from foo import *được sử dụng bởi chính mô-đun để sử dụng cho người khác ....
Nick T

using __all__ and import * is redundant, only __all__ is needed Làm thế nào là những người dư thừa? Họ làm những việc khác nhau.
endolith

112

Các __init__.pytập tin của tôi trống thường xuyên hơn không. Cụ thể, tôi không bao giờ có một from blah import *phần của __init__.py- nếu "nhập gói" có nghĩa là nhận tất cả các loại lớp, hàm vv được xác định trực tiếp như một phần của gói, thì tôi sẽ sao chép nội dung của blah.pygói __init__.pyvào thay thế và loại bỏ blah.py( sự nhân lên của các tập tin nguồn không tốt ở đây).

Nếu bạn khăng khăng ủng hộ các import *thành ngữ (eek), thì việc sử dụng __all__(với rất ít danh sách tên mà bạn có thể tự mang theo trong đó) có thể giúp kiểm soát thiệt hại. Nói chung, không gian tên và nhập khẩu rõ ràng là những điều tốt và tôi mạnh mẽ đề nghị xem xét lại bất kỳ phương pháp tiếp cận nào dựa trên việc bỏ qua một cách có hệ thống một hoặc cả hai khái niệm! -)


9
Cá nhân, tôi thích giữ mọi thứ riêng biệt, sau đó nhập *. Lý do là vì, mặc dù gấp và nhiều thứ, tôi vẫn ghét duyệt các tệp chứa quá nhiều lớp, ngay cả khi có liên quan.
Stefano Borini

5
@stefano nghĩ về một khuôn khổ lớn. nếu nó sử dụng, import *bạn phải chấp nhận vô điều kiện tất cả các khung công tác, ngay cả các tính năng bạn sẽ không bao giờ sử dụng. giữ __init__.pytrống cung cấp cho bạn nhiều cơ hội hơn chỉ là ngữ nghĩa tất cả hoặc không có gì. nghĩ về xoắn.
mg.

nếu để trống, ngay cả sau khi nhập mobilescouter, người ta vẫn không thể sử dụng mobilescouter.mapper hoặc mobilescouter.vehicle hoặc mobilescouter.whthing. không nhập mobilescouter.A, mobilescouter.B ..... quá dài dòng?
sunqiang

6
@sunqiang đây là cá nhân nhưng tôi không nghĩ vậy. from mobilescouter import A, Bchỉ là một dòng mã và bạn không có một dự án với 666 lớp và mỗi lớp có tệp riêng của mình, phải không? nếu bạn có hai hoặc nhiều hơn import *trong mã của mình, bạn sẽ lấp đầy không gian tên với rác tiềm năng và nhanh chóng bạn sẽ quên nơi Ađến từ đâu. Và nếu một gói trên làm tương tự? bạn đang lấy tất cả các gói phụ và gói phụ. Giống như zen của python nói, rõ ràng là tốt hơn ngầm.
mg.

1
@mg, nếu có một dòng "nhập A, B" trong tệp init .py, thì tôi có thể gọi A (hoặc B) với cú pháp: mobilescouter.A; nếu chúng ta sử dụng "từ mobilescouter nhập A, B", thì đó chỉ là A. một cái gì đó. đôi khi chỉ là dòng này, tôi không nhớ A là một nhánh phụ của mobilescouter và tôi nghĩ rằng điều này góp phần gây ô nhiễm không gian tên (mặc dù nó tốt hơn nhiều so với "" từ nhập mobilescouter * ". Tôi vẫn thích" nhập pkgname "cho người dùng giao diện công cộng thống nhất. Vì vậy, init .py thực hiện việc nhập sub_pkgname.
sunqiang

1

Bạn __init__.pynên có một chuỗi doc .

Mặc dù tất cả các chức năng được triển khai trong các mô-đun và gói phụ, chuỗi tài liệu gói của bạn là nơi để ghi lại nơi bắt đầu. Ví dụ, hãy xem xét gói pythonemail . Tài liệu gói là phần giới thiệu mô tả mục đích, bối cảnh và cách các thành phần khác nhau trong gói hoạt động cùng nhau. Nếu bạn tự động tạo tài liệu từ các tài liệu bằng cách sử dụng nhân sư hoặc gói khác, chuỗi tài liệu chính xác là nơi phù hợp để mô tả phần giới thiệu đó.

Đối với bất kỳ nội dung nào khác, hãy xem câu trả lời tuyệt vời của FirecrowAlex Martelli .


Có thực tế __init__.pycho các emailgói theo hướng dẫn này? Tôi thấy một chuỗi dòng duy nhất không làm được gì nhiều để giải thích "làm thế nào các thành phần khác nhau trong gói hoạt động cùng nhau".
Gertlex

@Gertlex Có lẽ chỉ trong tài liệu web.
gerrit
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.