Hướng dẫn dùng _init_.py python python

answer

1174

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

Python định nghĩa hai loại gói, gói thông thường và gói không gian tên. Các gói thông thường là các gói truyền thống khi chúng tồn tại trong Python 3.2 trở về trước. Một gói thông thường thường được thực hiện như một thư mục chứa một __init__.pytệp. Khi một gói thông thường được nhập, __init__.pytệp này được thực thi ngầm và các đối tượng mà nó xác định được liên kết với các tên trong không gian tên của gói. Các __init__.pytập tin có thể chứa mã Python tương tự mà bất kỳ thành phần khác có thể chứa, và Python sẽ bổ sung thêm một số thuộc tính bổ sung cho các mô-đun khi nó được nhập khẩu.

Nhưng chỉ cần nhấp vào liên kết, nó chứa một ví dụ, thêm thông tin và giải thích về các gói không gian tên, loại gói không có __init__.py.

1174 hữu ích 5 bình luận chia sẻ

answer

685

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

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

mydirtrên đường dẫn của bạn, bạn có thể nhập mã module.pydưới dạng

import spam.module

hoặc là

from spam import module

Nếu bạn xóa __init__.pytệp, Python sẽ không còn tìm các mô đun con trong thư mục đó nữa, vì vậy các nỗ lực nhập mô-đun sẽ thất bại.

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

import spam

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

685 hữu ích 2 bình luận chia sẻ

answer

407

Ngoài việc gắn nhãn thư mục là gói Python và xác định __all__, __init__.pycho 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 xác định 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 sự tuân thủ triết lý "phẳng hơn là lồng nhau" của Pythonic.

Một ví dụ

Dưới đây là một ví dụ từ một trong những dự án của tôi, trong đó tôi thường nhập một lệnh sessionmakergọi Sessionđể tương tác với cơ sở dữ liệu của mình. 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__.pychứa mã sau đây:

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 xác định Sessionở đây, tôi có thể bắt đầu một phiên mới bằng cú pháp bên dưới. Mã này sẽ được thực hiện giống nhau 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ỏ - giải pháp thay thế sẽ là xác định Sessiontrong 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 các 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 chủ đề reddit khá thú vị bao gồm các cách sử dụng thích hợp __init__.pyở đây:

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

Đa số ý kiến ​​dường như là __init__.pycác tệp nên rất mỏng để tránh vi phạm triết lý "rõ ràng là tốt hơn ngầm".

407 hữu ích 2 bình luận chia sẻ

answer

138

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 biết vị trí chính xác của các chức năng trong 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

    sau đó 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]

138 hữu ích 1 bình luận chia sẻ

answer

94

Các __init__.pytập tin làm cho danh bạ trị Python chứa nó như là 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 khi mô-đun được tải hoặc chỉ định các mô hình con được xuất.

94 hữu ích 0 bình luận chia sẻ

answer

69

Vì Python 3.3, __init__.pykhông còn cần thiết để xác định các thư mục là các gói Python có thể nhập được.

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

Hỗ trợ riêng cho các thư mục gói không yêu cầu __init__.pytệp đánh dấu và có thể tự động trải rộng trên nhiều phân đoạn đường dẫn [lấy cảm hứng từ các cách tiếp cận khác nhau của bên thứ ba đối với 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:
//docs.python.org/3/whatsnew/3.3.html#pep-420-implicit-namespace-packages
//www.python.org/dev/peps/pep-0420/
Is __init__. py không cần thiết cho các gói trong Python 3?

69 hữu ích 1 bình luận chia sẻ

answer

48

Trong Python định nghĩa của gói 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 là như nhau. Nhưng bạn phải có __init__.pytrong một gói. Tôi sẽ giải thích các __init__.pytập tin với ví dụ dưới đây:

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__.pycó thể trống rỗ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__.pycũng có thể thiết lập nội dung phù 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 module_n1 là hàm. Chúng tôi có thể sử dụng __init__.pytrong 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 "", line 1, in 
ImportError: No module named module_n1

Do đó sử dụng * nhập, gói mô-đun là tùy thuộc vào __init__.pynội dung.

48 hữu ích 0 bình luận chia sẻ

answer

37

__init__.py sẽ coi thư mục của nó là một mô-đun có thể tải.

Đối với những người thích đọc mã, tôi đặt bình luận của Nhà giả kim Two-Bit ở đâ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 "", line 1, in 
ImportError: No module named spam
>>> 

37 hữu ích 0 bình luận chia sẻ

answer

30

Mặc dù Python hoạt động mà không có __init__.pytệp, bạn vẫn nên bao gồm một tệp.

Nó chỉ định một gói nên được coi là một mô-đun, do đó bao gồm nó [ngay cả khi nó trống].

Cũng có trường hợp bạn thực sự có thể sử dụng một __init__.pytệp:

Hãy tưởng tượng bạn có cấu trúc tệp sau:

main_methods 
    |- methods.py

methods.pycó chứa điều này:

def foo[]:
    return 'foo'

Để sử dụng, foo[]bạn cần một trong những điều sau đây:

from main_methods.methods import foo # Call with foo[]
from main_methods import methods # Call with methods.foo[]
import main_methods.methods # Call with main_methods.methods.foo[]

Có thể ở đó bạn cần [hoặc muốn] để giữ methods.pybên trong main_methods[thời gian chạy / phụ thuộc chẳng hạn] nhưng bạn chỉ muốn nhập main_methods.

Nếu bạn đã thay đổi tên của methods.pyđể __init__.pysau đó bạn có thể sử dụng foo[]bằng cách chỉ nhập khẩu main_methods:

import main_methods
print[main_methods.foo[]] # Prints 'foo'

Điều này hoạt động vì __init__.pyđược coi là một phần của gói.

Một số gói Python thực sự làm điều này. Một ví dụ là với JSON , nơi chạy import jsonthực sự là nhập __init__.pytừ jsongói [ xem cấu trúc tệp gói ở đây ]:

Mã nguồn: Lib/json/__init__.py

30 hữu ích 0 bình luận chia sẻ

Chủ Đề