Câu hỏi __Init__.py là gì?


Những gì là __init__.py trong thư mục nguồn Python?


1418
2018-01-15 20:09


gốc


Theo nhận xét bên dưới bởi @Rob_before_edits và luồng stackoverflow này 37139786, có vẻ như trong đó.py không còn cần thiết cho Python 3.3+. - Jun


Các câu trả lời:


Nó là một phần của một gói. Đây là tài liệu.

Các __init__.py các tệp được yêu cầu để làm cho Python xử lý các thư mục có chứa các gói; điều này được thực hiện để ngăn các thư mục có tên chung, chẳng hạn như string, từ vô tình ẩn các mô-đun hợp lệ xảy ra sau này (sâu hơn) trên đường dẫn tìm kiếm mô-đun. Trong trường hợp đơn giản nhất, __init__.py có thể chỉ là một tệp rỗng, nhưng nó cũng có thể thực thi mã khởi tạo cho gói hoặc thiết lập __all__ biến, được mô tả sau.


979
2018-01-15 20:13



Điều này có nghĩa là: "điều này được thực hiện để ngăn các thư mục có tên chung, chẳng hạn như chuỗi, từ vô tình ẩn các mô-đun hợp lệ xảy ra sau này trên đường dẫn tìm kiếm mô-đun"? - Carl G
@CarlG Python tìm kiếm danh sách các thư mục để giải quyết tên trong, ví dụ: báo cáo nhập. Bởi vì chúng có thể là bất kỳ thư mục nào và những người tùy ý có thể được thêm vào bởi người dùng cuối, các nhà phát triển phải lo lắng về các thư mục xảy ra để chia sẻ tên với một mô-đun Python hợp lệ, chẳng hạn như 'chuỗi' trong ví dụ tài liệu. Để giảm bớt điều này, nó bỏ qua các thư mục không chứa một tệp có tên _ _ init _ _.py (không có dấu cách), ngay cả khi nó trống. - Two-Bit Alchemist
@CarlG Hãy thử điều này. Tạo một thư mục có tên 'datetime' và trong đó tạo hai tệp trống, tệp init.py (có dấu gạch dưới) và datetime.py. Bây giờ mở một thông dịch viên, nhập sys và phát hành sys.path.insert(0, '/path/to/datetime'), thay thế đường dẫn đó bằng đường dẫn đến bất kỳ thư mục nào bạn vừa tạo. Bây giờ hãy thử một cái gì đó như from datetime import datetime;datetime.now(). Bạn sẽ nhận được một AttributeError (vì nó đang nhập tệp trống của bạn bây giờ). Nếu bạn đã lặp lại các bước này mà không tạo tệp init trống, điều này sẽ không xảy ra. Đó là những gì nó dự định để ngăn chặn. - Two-Bit Alchemist
@ DarekNędza Bạn đã thiết lập một thứ gì đó không chính xác nếu bạn không thể mở một trình thông dịch và vấn đề Python from datetime import datetime không có lỗi. Đó là tốt tất cả các cách trở lại phiên bản 2.3! - Two-Bit Alchemist
@SWang: Không đúng: builtins danh sách được tích hợp sẵn chức năng và các lớp học, không được xây dựng trong các mô-đun (cf. docs.python.org/3/tutorial/modules.html#the-dir-function). Nếu bạn muốn liệt kê tích hợp mô-đun, làm import sys; print(sys.builtin_module_names) (cf. docs.python.org/3/library/sys.html#sys.builtin_module_names). - Maggyero


Tệp có tên __init__.py được sử dụng để đánh dấu các thư mục trên đĩa là các thư mục gói Python. Nếu bạn có các tệp

mydir/spam/__init__.py
mydir/spam/module.py

mydir là trên đường dẫn của bạn, bạn có thể nhập mã vào module.py như

import spam.module

hoặc là

from spam import module

Nếu bạn xóa __init__.py tập tin, Python sẽ không còn tìm kiếm submodules bên trong thư mục đó, do đó, các nỗ lực để nhập khẩu mô-đun sẽ thất bại.

Các __init__.py tệp thường trống, nhưng có thể được sử dụng để xuất các phần đã chọn của gói dưới tên thuận tiện hơn, giữ các chức năng tiện lợi, v.v. Cho ví dụ trên, nội dung của mô-đun init có thể được truy cập như

import spam

dựa trên điều này


598
2017-11-07 03:31



Cập nhật: Tệp __init__.py được yêu cầu theo Python 2.X và vẫn được yêu cầu theo Python 2.7.12 (tôi đã thử nghiệm nó) nhưng nó không còn được yêu cầu từ (được cho là) ​​Python 3.3 trở đi, và không bắt buộc theo Python 3.4.3 (tôi đã thử nghiệm nó). Xem stackoverflow.com/questions/37139786 để biết thêm chi tiết. - Rob_before_edits


Ngoài việc gắn nhãn một thư mục dưới dạng gói Python và xác định __all__, __init__.py cho phép bạn xác định bất kỳ biến nào ở cấp gói. Làm như vậy thường thuận tiện nếu một gói định nghĩa thứ gì đó sẽ được nhập thường xuyên, theo kiểu giống như API. Mô hình này thúc đẩy việc tuân thủ triết lý "phẳng" tốt hơn so với lồng nhau "".

Một ví dụ

Dưới đây là một ví dụ từ một trong các dự án của tôi, trong đó tôi thường xuyên nhập sessionmaker gọi là Session để tương tác với cơ sở dữ liệu của tôi. Tôi đã viết một gói "cơ sở dữ liệu" với một vài mô-đun:

database/
    __init__.py
    schema.py
    insertions.py
    queries.py

Của tôi __init__.py chứa mã sau:

import os

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine

engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)

Vì tôi định nghĩa Session ở đây, tôi có thể bắt đầu một phiên mới bằng cách sử dụng cú pháp dưới đây. Mã này sẽ được thực thi tương tự từ bên trong hoặc bên ngoài thư mục gói "cơ sở dữ liệu".

from database import Session
session = Session()

Tất nhiên, đây là một sự thuận tiện nhỏ - thay thế sẽ là để xác định Session trong một tệp mới như "create_session.py" trong gói cơ sở dữ liệu của tôi và bắt đầu phiên mới bằng cách sử dụng:

from database.create_session import Session
session = Session()

đọc thêm

Có một chuỗi reddit khá thú vị bao gồm việc sử dụng thích hợp __init__.py đây:

http://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_include_in_init_py/

Phần lớn ý kiến ​​dường như là __init__.py các tệp phải rất mỏng để tránh vi phạm triết lý "rõ ràng là tốt hơn là ẩn".


366
2017-09-24 10:38



engine, sessionmaker, create_enginevà os tất cả cũng có thể được nhập từ database bây giờ ... có vẻ như bạn đã thực hiện một mớ hỗn độn của không gian tên đó. - ArtOfWarfare
@ArtOfWarfare, bạn có thể sử dụng __all__ = [...] để giới hạn những gì được nhập bằng import *. Nhưng ngoài việc đó, có, bạn còn lại với một không gian tên lộn xộn cấp cao nhất. - Nathan Gould


Có 2 lý do chính cho __init__.py

  1. Để thuận tiện: những người dùng khác sẽ không cần phải biết vị trí chính xác của chức năng của bạn trong hệ thống phân cấp gói của bạn.

    your_package/
      __init__.py
      file1.py/
      file2.py/
        ...
      fileN.py
    
    # in __init__.py
    from file1 import *
    from file2 import *
    ...
    from fileN import *
    
    # in file1.py
    def add():
        pass
    

    thì những người khác có thể gọi add () bằng

    from your_package import add
    

    mà không biết file1, như

    from your_package.file1 import add
    
  2. Nếu bạn muốn một cái gì đó được khởi tạo; ví dụ: ghi nhật ký (cần được đặt ở cấp cao nhất):

    import logging.config
    logging.config.dictConfig(Your_logging_config)
    

104
2018-04-08 08:29



oh, trước khi đọc câu trả lời của bạn, tôi nghĩ gọi một hàm rõ ràng từ vị trí của nó là một thực hành tốt. - Aaron


Các __init__.py tập tin làm cho Python xử lý các thư mục có chứa nó như là các mô-đun.

Hơn nữa, đây là tệp đầu tiên được tải trong một mô-đun, vì vậy bạn có thể sử dụng nó để thực thi mã mà bạn muốn chạy mỗi lần mô-đun được tải, hoặc chỉ định các mô-đun con được xuất.


87
2018-01-15 20:22





Kể từ Python 3.3, __init__.py không còn cần thiết để định nghĩa các thư mục như các gói Python có thể nhập khẩu được nữa.

Kiểm tra PEP 420: Gói không gian tên ngầm định:

Hỗ trợ gốc cho các thư mục gói không yêu cầu __init__.py các tệp đánh dấu và có thể tự động mở rộng nhiều đoạn đường dẫn (lấy cảm hứng từ các cách tiếp cận của bên thứ ba khác nhau cho các gói không gian tên, như được mô tả trong PEP 420)

Đây là bài kiểm tra:

$ mkdir -p /tmp/test_init
$ touch /tmp/test_init/module.py /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
├── module.py
└── __init__.py
$ python3

>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module

$ rm -f /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
└── module.py
$ python3

>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module

tài liệu tham khảo:
https://docs.python.org/3/whatsnew/3.3.html#pep-420-implicit-namespace-packages
https://www.python.org/dev/peps/pep-0420/
__Init__.py có bắt buộc đối với các gói trong Python 3 không? 


46
2017-10-12 06:36





Trong Python định nghĩa của gói là rất đơn giản. Giống như Java cấu trúc phân cấp và cấu trúc thư mục giống nhau. Nhưng bạn phải có __init__.py trong một gói. Tôi sẽ giải thích __init__.py tệp với ví dụ bên dưới:

package_x/
|--  __init__.py
|--    subPackage_a/
|------  __init__.py
|------  module_m1.py
|--    subPackage_b/
|------  __init__.py
|------  module_n1.py
|------  module_n2.py
|------  module_n3.py

__init__.py có thể để trống, miễn là nó tồn tại. Nó chỉ ra rằng thư mục nên được coi là một gói. Tất nhiên, __init__.py cũng có thể đặt nội dung thích hợp.

Nếu chúng ta thêm một hàm trong module_n1:

def function_X():
    print "function_X in module_n1"
    return

Sau khi chạy:

>>>from package_x.subPackage_b.module_n1 import function_X
>>>function_X()

function_X in module_n1 

Sau đó, chúng tôi đã theo gói phân cấp và gọi hàm module_n1. Chúng ta có thể sử dụng __init__.py trong subPackage_b như thế này:

__all__ = ['module_n2', 'module_n3']

Sau khi chạy:

>>>from package_x.subPackage_b import * 
>>>module_n1.function_X()

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named module_n1

Do đó sử dụng * nhập khẩu, gói mô-đun có thể __init__.py Nội dung.


44
2018-01-09 11:45





__init__.py sẽ xử lý thư mục đó như là một mô-đun có thể nạp được.

Đối với những người thích đọc mã, tôi đặt Two-Bit Alchemist's bình luận ở đây

$ find /tmp/mydir/
/tmp/mydir/
/tmp/mydir//spam
/tmp/mydir//spam/__init__.py
/tmp/mydir//spam/module.py
$ cd ~
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
>>> module.myfun(3)
9
>>> exit()
$ 
$ rm /tmp/mydir/spam/__init__.py*
$ 
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named spam
>>> 

35
2018-01-03 17:41





__Init__.py được sử dụng để làm gì?

Việc sử dụng chính của __init__.py là để khởi tạo các gói Python. Cách dễ nhất để chứng minh điều này là xem xét cấu trúc của một mô-đun Python chuẩn.

package/
    __init__.py
    file.py
    file2.py
    file3.py
    subpackage/
        __init__.py
        submodule1.py
        submodule2.py

Như bạn có thể thấy trong cấu trúc bên trên sự bao gồm của __init__.py tệp trong một thư mục chỉ ra cho trình thông dịch Python rằng thư mục cần được xử lý như một gói Python

Điều gì xảy ra __init__.py?

__init__.py có thể là một tệp rỗng nhưng nó thường được sử dụng để thực hiện thiết lập cần thiết cho gói (nhập mọi thứ, tải mọi thứ vào đường dẫn, v.v.).

Một điều phổ biến cần làm trong __init__.py là nhập các Lớp, chức năng được chọn, v.v. vào mức gói để chúng có thể được nhập khẩu một cách thuận tiện từ gói.

Trong ví dụ trên chúng ta có thể nói rằng file.py có File Class. Vì vậy, không có gì trong __init__.py bạn sẽ nhập bằng cú pháp này:

from package.file import File

Tuy nhiên bạn có thể nhập tệp vào __init__.py để làm cho nó có sẵn ở cấp gói:

# in your __init__.py
from file import File

# now import File from package
from package import File

Một điều cần làm là ở cấp gói làm cho các gói con / mô-đun có sẵn với __all__ biến. Khi interpeter thấy một __all__ biến được định nghĩa trong một __init__.py nó nhập khẩu các mô-đun được liệt kê trong __all__ biến khi bạn làm:

from package import *

__all__là danh sách chứa tên mô-đun mà bạn muốn được nhập bằng nhập * để xem lại ví dụ trên nếu chúng ta muốn nhập các mô-đun con trong gói con __all__ biến trong subpackage/__init__.py sẽ là:

__all__ = ['submodule1', 'submodule2']

Với __all__ biến dân cư như thế, khi bạn biểu diễn

from subpackage import *

nó sẽ nhập submodule1 và submodule2.

Bạn có thể thấy __init__.py có thể rất hữu ích bên cạnh chức năng chính của nó chỉ ra rằng một thư mục là một mô-đun.

Tài liệu tham khảo


28
2017-12-17 06:09



Bạn nên trỏ đến nguồn gốc của câu trả lời này: mikegrouchy.com/blog/2012/05/be-pythonic-__init__py.html - Ayushi Dalmia
@AyushiDalmia, tôi đã cập nhật câu trả lời của mình. - Chirag Maliwal


Nó tạo điều kiện cho việc nhập khẩu các tệp python khác. Khi bạn đặt tập tin này trong một thư mục (nói công cụ) có chứa các tập tin py khác, sau đó bạn có thể làm một cái gì đó giống như import stuff.other.

root\
    stuff\
         other.py

    morestuff\
         another.py

Không có điều này __init__.py bên trong thư mục, bạn không thể nhập other.py, bởi vì Python không biết mã nguồn của công cụ ở đâu và không thể nhận ra nó là một gói.


25
2018-01-15 20:18



Điều này chỉ hoạt động nếu tất cả các thư mục con là các thư mục con của cùng một thư mục cha. - gented