Ai đó có thể giải thích __all__ bằng Python không?


983

Tôi đã sử dụng Python ngày càng nhiều và tôi vẫn thấy biến __all__được đặt trong các __init__.pytệp khác nhau . Ai đó có thể giải thích điều này không?

Câu trả lời:


566

Đây là danh sách các đối tượng công khai của mô-đun đó, như được giải thích bởi import *. Nó ghi đè mặc định của việc ẩn mọi thứ bắt đầu bằng dấu gạch dưới.


146
Các đối tượng bắt đầu bằng dấu gạch dưới hoặc không được đề cập trong __all__nếu __all__có, không được ẩn chính xác; họ có thể được nhìn thấy và truy cập hoàn toàn bình thường nếu bạn biết tên của họ. Chỉ trong trường hợp "nhập *", dù sao không được khuyến nghị, sự khác biệt mang bất kỳ trọng lượng nào.
Brandon Rhodes

28
@BrandonRhodes: điều đó cũng không chính xác: Bạn chỉ nên nhập các mô-đun mà bạn biết sẽ được thiết kế cho import *(ví dụ như tk). Một gợi ý hay nếu đây là trường hợp là sự hiện diện của __all__hoặc tên bắt đầu bằng dấu gạch dưới trong mã của mô-đun.
cừu bay

12
Giao diện công cộng và nội bộ - python.org/dev/peps/pep-0008/#id50 , Để hỗ trợ nội tâm tốt hơn, các mô-đun nên khai báo rõ ràng tên trong API công khai của chúng bằng thuộc tính __all__. Đặt __all__ thành một danh sách trống cho biết mô-đun không có API công khai.
gỡ lỗi

Tôi không chắc chắn rằng nếu tkđược phát hành ngày hôm nay (hoặc trong năm 2012, thậm chí), thực tế được khuyến nghị sẽ là sử dụng from tk import *. Tôi nghĩ rằng thực tế được chấp nhận do quán tính, không phải thiết kế có chủ ý.
chepner

Như BrandonRhodes chỉ ra rằng điều này thực sự không chính xác
vào

947

Liên kết đến, nhưng không được đề cập rõ ràng ở đây, chính xác __all__là khi được sử dụng. Nó là một danh sách các chuỗi xác định những ký hiệu nào trong mô-đun sẽ được xuất khi from <module> import *được sử dụng trên mô-đun.

Ví dụ: đoạn mã sau đây foo.pyxuất rõ ràng các ký hiệu barbaz:

__all__ = ['bar', 'baz']

waz = 5
bar = 10
def baz(): return 'baz'

Những biểu tượng này sau đó có thể được nhập như vậy:

from foo import *

print(bar)
print(baz)

# The following will trigger an exception, as "waz" is not exported by the module
print(waz)

Nếu __all__nhận xét ở trên, mã này sẽ thực thi đến khi hoàn thành, vì hành vi mặc định import *là nhập tất cả các ký hiệu không bắt đầu bằng dấu gạch dưới, từ không gian tên đã cho.

Tham khảo: https://docs.python.org/tutorial/modules.html#importing-from-a-package

LƯU Ý: chỉ __all__ ảnh hưởng đến from <module> import *hành vi. Các thành viên không được đề cập đến __all__vẫn có thể truy cập từ bên ngoài mô-đun và có thể được nhập với from <module> import <member>.


1
chúng ta không nên in baz như print(baz())?
John Cole

@JohnCole baz là đối tượng hàm và baz () sẽ chạy đối tượng hàm
Bhanu Tez

@BhanuTez chính xác. Vì vậy, print(baz)in một cái gì đó giống như <function baz at 0x7f32bc363c10>trong khi print(baz())inbaz
John Cole

223

Giải thích __all__ trong Python?

Tôi tiếp tục nhìn thấy các biến __all__được thiết lập trong các __init__.pytập tin khác nhau .

Cái này làm gì

Không gì __all__làm gì?

Nó tuyên bố các tên "công khai" về mặt ngữ nghĩa từ một mô-đun. Nếu có tên __all__, người dùng sẽ sử dụng nó và họ có thể mong đợi rằng nó sẽ không thay đổi.

Nó cũng sẽ có ảnh hưởng đến chương trình:

import *

__all__trong một mô-đun, ví dụ module.py:

__all__ = ['foo', 'Bar']

có nghĩa là khi bạn import *từ mô-đun, chỉ những tên trong phần __all__được nhập:

from module import *               # imports foo and Bar

Công cụ tài liệu

Các công cụ tự động hoàn thành tài liệu và mã có thể (trên thực tế, cũng nên) kiểm tra __all__để xác định tên nào sẽ hiển thị khi có sẵn từ một mô-đun.

__init__.py làm cho một thư mục một gói Python

Từ các tài liệu :

Các __init__.pytệp được yêu cầu để làm cho Python coi các thư mục là 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ư chuỗi, vô tình che giấu các mô-đun hợp lệ xảy ra sau này trên đường dẫn tìm kiếm mô-đun.

Trong trường hợp đơn giản nhất, __init__.pycó thể chỉ là một tệp trống, nhưng nó cũng có thể thực thi mã khởi tạo cho gói hoặc đặt __all__biến.

Vì vậy, __init__.pycó thể tuyên bố __all__cho một gói .

Quản lý API:

Một gói thường được tạo thành từ các mô-đun có thể nhập lẫn nhau, nhưng nhất thiết phải được gắn với nhau bằng một __init__.pytệp. Tệp đó là thứ làm cho thư mục trở thành một gói Python thực sự. Ví dụ: giả sử bạn có các tệp sau trong một gói:

package
├── __init__.py
├── module_1.py
└── module_2.py

Hãy tạo các tệp này bằng Python để bạn có thể theo dõi - bạn có thể dán đoạn sau vào trình bao Python 3:

from pathlib import Path

package = Path('package')
package.mkdir()

(package / '__init__.py').write_text("""
from .module_1 import *
from .module_2 import *
""")

package_module_1 = package / 'module_1.py'
package_module_1.write_text("""
__all__ = ['foo']
imp_detail1 = imp_detail2 = imp_detail3 = None
def foo(): pass
""")

package_module_2 = package / 'module_2.py'
package_module_2.write_text("""
__all__ = ['Bar']
imp_detail1 = imp_detail2 = imp_detail3 = None
class Bar: pass
""")

Và bây giờ bạn đã trình bày một api hoàn chỉnh mà người khác có thể sử dụng khi họ nhập gói của bạn, như vậy:

import package
package.foo()
package.Bar()

Và gói sẽ không có tất cả các chi tiết triển khai khác mà bạn đã sử dụng khi tạo các mô-đun của mình làm lộn xộn packagekhông gian tên.

__all__ trong __init__.py

Sau khi làm việc nhiều hơn, có thể bạn đã quyết định rằng các mô-đun quá lớn (như hàng ngàn dòng?) Và cần phải được tách ra. Vì vậy, bạn làm như sau:

package
├── __init__.py
├── module_1
│   ├── foo_implementation.py
│   └── __init__.py
└── module_2
    ├── Bar_implementation.py
    └── __init__.py

Đầu tiên tạo các thư mục gói con có cùng tên với các mô-đun:

subpackage_1 = package / 'module_1'
subpackage_1.mkdir()
subpackage_2 = package / 'module_2'
subpackage_2.mkdir()

Di chuyển các triển khai:

package_module_1.rename(subpackage_1 / 'foo_implementation.py')
package_module_2.rename(subpackage_2 / 'Bar_implementation.py')

tạo __init__.pys cho các gói con khai báo __all__cho mỗi gói:

(subpackage_1 / '__init__.py').write_text("""
from .foo_implementation import *
__all__ = ['foo']
""")
(subpackage_2 / '__init__.py').write_text("""
from .Bar_implementation import *
__all__ = ['Bar']
""")

Và bây giờ bạn vẫn có api được cung cấp ở cấp gói:

>>> import package
>>> package.foo()
>>> package.Bar()
<package.module_2.Bar_implementation.Bar object at 0x7f0c2349d210>

Và bạn có thể dễ dàng thêm mọi thứ vào API mà bạn có thể quản lý ở cấp gói phụ thay vì cấp mô-đun của gói phụ. Nếu bạn muốn thêm tên mới vào API, bạn chỉ cần cập nhật __init__.py, ví dụ như trong mô-đun_2:

from .Bar_implementation import *
from .Baz_implementation import *
__all__ = ['Bar', 'Baz']

Và nếu bạn chưa sẵn sàng để xuất bản Baztrong API cấp cao nhất, thì ở cấp cao nhất __init__.pybạn có thể có:

from .module_1 import *       # also constrained by __all__'s
from .module_2 import *       # in the __init__.py's
__all__ = ['foo', 'Bar']     # further constraining the names advertised

và nếu người dùng của bạn biết về tính khả dụng của Baz, họ có thể sử dụng nó:

import package
package.Baz()

nhưng nếu họ không biết về nó, các công cụ khác (như pydoc ) sẽ không thông báo cho họ.

Sau này bạn có thể thay đổi điều đó khi Bazsẵn sàng cho giờ chính:

from .module_1 import *
from .module_2 import *
__all__ = ['foo', 'Bar', 'Baz']

Tiền tố _so với __all__:

Theo mặc định, Python sẽ xuất tất cả các tên không bắt đầu bằng một _. Bạn chắc chắn có thể dựa vào cơ chế này. Một số gói trong thư viện chuẩn của Python, trên thực tế, làm dựa vào điều này, nhưng để làm như vậy, họ alias nhập khẩu của họ, ví dụ, trong ctypes/__init__.py:

import os as _os, sys as _sys

Sử dụng _ quy ước có thể thanh lịch hơn vì nó loại bỏ sự dư thừa của việc đặt tên một lần nữa. Nhưng nó bổ sung thêm sự dư thừa cho hàng nhập khẩu (nếu bạn có rất nhiều trong số đó) và rất dễ quên làm điều này một cách nhất quán - và điều cuối cùng bạn muốn là phải hỗ trợ vô hạn một cái gì đó mà bạn dự định chỉ là một chi tiết thực hiện, chỉ là bởi vì bạn đã quên tiền tố một _khi đặt tên hàm.

Cá nhân tôi viết __all__sớm trong vòng đời phát triển của mình cho các mô-đun để những người khác có thể sử dụng mã của tôi biết họ nên sử dụng cái gì và không sử dụng.

Hầu hết các gói trong thư viện tiêu chuẩn cũng sử dụng __all__.

Khi tránh __all__ có ý nghĩa

Nó có ý nghĩa để gắn bó với _quy ước tiền tố thay cho__all__ khi:

  • Bạn vẫn đang ở chế độ phát triển sớm và không có người dùng và liên tục điều chỉnh API của bạn.
  • Có thể bạn có người dùng, nhưng bạn có những điều không hợp lý bao trùm API và bạn vẫn đang tích cực thêm vào API và điều chỉnh trong quá trình phát triển.

Một exportngười trang trí

Nhược điểm của việc sử dụng __all__là bạn phải viết tên của các hàm và lớp được xuất hai lần - và thông tin được tách biệt khỏi các định nghĩa. Chúng ta có thể sử dụng một trang trí để giải quyết vấn đề này.

Tôi có ý tưởng cho một nhà trang trí xuất khẩu như vậy từ bài nói chuyện của David Beazley về bao bì. Việc triển khai này dường như hoạt động tốt trong nhà nhập khẩu truyền thống của CPython. Nếu bạn có một hệ thống hoặc móc nhập khẩu đặc biệt, tôi không đảm bảo, nhưng nếu bạn chấp nhận nó, việc rút lui khá đơn giản - bạn sẽ chỉ cần thêm tên thủ công vào__all__

Vì vậy, trong ví dụ, một thư viện tiện ích, bạn sẽ xác định trình trang trí:

import sys

def export(fn):
    mod = sys.modules[fn.__module__]
    if hasattr(mod, '__all__'):
        mod.__all__.append(fn.__name__)
    else:
        mod.__all__ = [fn.__name__]
    return fn

và sau đó, nơi bạn sẽ xác định một __all__, bạn làm điều này:

$ cat > main.py
from lib import export
__all__ = [] # optional - we create a list if __all__ is not there.

@export
def foo(): pass

@export
def bar():
    'bar'

def main():
    print('main')

if __name__ == '__main__':
    main()

Và điều này hoạt động tốt cho dù chạy như chính hoặc nhập bởi chức năng khác.

$ cat > run.py
import main
main.main()

$ python run.py
main

Và việc cung cấp API import *cũng sẽ hoạt động:

$ cat > run.py
from main import *
foo()
bar()
main() # expected to error here, not exported

$ python run.py
Traceback (most recent call last):
  File "run.py", line 4, in <module>
    main() # expected to error here, not exported
NameError: name 'main' is not defined

1
Tham khảo chéo: Tôi đã đề cập đến trang trí của bạn trong câu trả lời CW này cho câu hỏi làm thế nào để viết một @exporttrang trí.
MvG

13
Đây chỉ là một câu trả lời hữu ích nhất mà tôi từng thấy liên quan đến việc giúp một nhà phát triển trăn tương đối mới hiểu được quy trình nhập mô-đun / gói __init__.pyvà sử dụng__all__
Brett Reinhard

Điều này giúp tôi rất nhiều. Vấn đề của tôi, tho, đó là các mô hình con tôi muốn nhập là tất cả các tệp được tạo với rất nhiều ký hiệu trong biểu tượng mà chúng muốn loại bỏ, mà không phải đảm bảo __all__chính xác.
Mike C

@MikeC thì có lẽ bạn cũng nên tạo ra __all__- nhưng sau đó tôi sẽ nói rằng bạn có API không ổn định ... Đây sẽ là một cái gì đó để có một số thử nghiệm chấp nhận toàn diện trên.
Aaron Hall

@AaronHall "họ sẽ không có tất cả các tên khác ... làm lộn xộn không gian tên gói" Nhưng họ sẽ có tên module_1module_2; Có thể bao gồm một rõ ràng del module_1trong __init__.py? Tôi có sai khi nghĩ rằng điều này là đáng giá?
Mike C

176

Tôi chỉ thêm điều này cho chính xác:

Tất cả các câu trả lời khác đề cập đến các mô-đun . Câu hỏi ban đầu được đề cập rõ ràng __all__trong __init__.pycác tập tin, vì vậy đây là về các gói python .

Nói chung, __all__chỉ có hiệu lực khi from xxx import *biến thể của importcâu lệnh được sử dụng. Điều này áp dụng cho các gói cũng như các mô-đun.

Hành vi cho các mô-đun được giải thích trong các câu trả lời khác. Hành vi chính xác cho các gói được mô tả chi tiết ở đây .

Nói tóm lại, __all__ở cấp độ gói thực hiện gần giống như với các mô-đun, ngoại trừ nó liên quan đến các mô-đun trong gói (ngược lại với việc chỉ định tên trong mô-đun ). Vì vậy, __all__chỉ định tất cả các mô-đun sẽ được tải và nhập vào không gian tên hiện tại khi chúng tôi sử dụng from package import *.

Sự khác biệt lớn là, khi bạn bỏ qua phần khai báo __all__trong gói __init__.py, câu lệnh from package import *sẽ không nhập bất cứ thứ gì cả (với các trường hợp ngoại lệ được giải thích trong tài liệu, xem liên kết ở trên).

Mặt khác, nếu bạn bỏ qua __all__trong một mô-đun, "nhập có gắn dấu sao" sẽ nhập tất cả các tên (không bắt đầu bằng dấu gạch dưới) được xác định trong mô-đun.


29
from package import *vẫn sẽ nhập mọi thứ được xác định trong __init__.py, ngay cả khi không có all. Sự khác biệt quan trọng là nếu không có __all__nó sẽ không tự động nhập bất kỳ mô-đun nào được xác định trong thư mục của gói.
Nikratio

Khi tất cả có chứa [foo, bar] và trong tệp test.txt nếu chúng ta sử dụng: từ nhập gói *, thì, foo và thanh có được nhập trong không gian tên cục bộ của test.txt hoặc trong không gian tên riêng của foo và thanh không?
biến

87

Nó cũng thay đổi những gì pydoc sẽ hiển thị:

module1.py

a = "A"
b = "B"
c = "C"

module2.py

__all__ = ['a', 'b']

a = "A"
b = "B"
c = "C"

$ pydoc mô đun1

Trợ giúp về mô-đun mô-đun1:

TÊN
    mô-đun 1

TẬP TIN
    module1.py

DỮ LIỆU 
    a = 'A'
     b = 'B'
     c = 'C'

$ pydoc module2

Trợ giúp về module module2:

TÊN
    mô đun2

TẬP TIN
    module2.py

DỮ LIỆU 
    __all__ = ['a', 'b']
     a = 'A'
     b = 'B'

Tôi tuyên bố __all__trong tất cả các mô-đun của mình, cũng như các chi tiết bên trong gạch dưới, những điều này thực sự hữu ích khi sử dụng những thứ bạn chưa từng sử dụng trước đây trong các phiên dịch trực tiếp.


54

__all__tùy chỉnh *trongfrom <module> import *

__all__tùy chỉnh *trongfrom <package> import *


Một mô-đun là một .pytập tin có nghĩa là để nhập khẩu.

Một gói là một thư mục với một __init__.pytập tin. Một gói thường chứa các mô-đun.


PHƯƠNG THỨC

""" cheese.py - an example module """

__all__ = ['swiss', 'cheddar']

swiss = 4.99
cheddar = 3.99
gouda = 10.99

__all__cho phép con người biết các tính năng "công khai" của một mô-đun . [ @AaronHall ] Ngoài ra, pydoc nhận ra chúng. [ @Longpoke ]

từ nhập mô-đun *

Xem cách swisscheddarđược đưa vào không gian tên cục bộ, nhưng không gouda:

>>> from cheese import *
>>> swiss, cheddar
(4.99, 3.99)
>>> gouda
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'gouda' is not defined

Nếu không __all__, bất kỳ biểu tượng nào (không bắt đầu bằng dấu gạch dưới) sẽ có sẵn.


Nhập khẩu mà *không bị ảnh hưởng bởi__all__


mô-đun nhập khẩu

>>> import cheese
>>> cheese.swiss, cheese.cheddar, cheese.gouda
(4.99, 3.99, 10.99)

từ tên nhập mô-đun

>>> from cheese import swiss, cheddar, gouda
>>> swiss, cheddar, gouda
(4.99, 3.99, 10.99)

nhập mô-đun làm tên địa phương

>>> import cheese as ch
>>> ch.swiss, ch.cheddar, ch.gouda
(4.99, 3.99, 10.99)

GÓI

Trong __init__.pytệp của gói __all__ là một danh sách các chuỗi với tên của các mô-đun công khai hoặc các đối tượng khác. Những tính năng có sẵn để nhập ký tự đại diện. Cũng như các mô-đun, __all__tùy chỉnh *khi nhập ký tự đại diện từ gói. [ @MartinStettner ]

Đây là một đoạn trích từ Trình kết nối Python của Python __init__.py :

__all__ = [
    'MySQLConnection', 'Connect', 'custom_error_exception',

    # Some useful constants
    'FieldType', 'FieldFlag', 'ClientFlag', 'CharacterSet', 'RefreshOption',
    'HAVE_CEXT',

    # Error handling
    'Error', 'Warning',

    ...etc...

    ]

Trường hợp mặc định, dấu hoa thị không có __all__gói , rất phức tạp, vì hành vi rõ ràng sẽ tốn kém: sử dụng hệ thống tệp để tìm kiếm tất cả các mô-đun trong gói. Thay vào đó, trong quá trình đọc tài liệu của tôi, chỉ các đối tượng được xác định trong __init__.pyđược nhập:

Nếu __all__không được xác định, báo cáo kết quả from sound.effects import *nào không nhập khẩu tất cả các môđun con từ gói sound.effectsvào namespace hiện hành; nó chỉ đảm bảo rằng gói sound.effectsđã được nhập (có thể chạy bất kỳ mã khởi tạo nào __init__.py) và sau đó nhập bất kỳ tên nào được xác định trong gói. Điều này bao gồm bất kỳ tên nào được xác định (và các mô hình con được tải rõ ràng) bởi __init__.py. Nó cũng bao gồm bất kỳ mô hình con nào của gói được tải rõ ràng bằng các câu lệnh nhập trước đó.


Nhập ký tự đại diện ... nên tránh vì chúng gây nhầm lẫn cho người đọc và nhiều công cụ tự động.

[ PEP 8 , @ToolmakerSteve]


2
Tôi thực sự thích câu trả lời này, nhưng tôi thiếu thông tin về hành vi mặc định from <package> import *mà không có __all__trong __init__.pyđó là không nhập bất kỳ mô-đun nào .
radzak

Cảm ơn @Jatimir, tôi đã làm rõ nhất có thể mà không cần chạy thử nghiệm. Tôi gần như muốn nói trường hợp này (dấu hoa thị mà không có tất cả cho một gói) hoạt động giống như __init__.pylà một mô-đun . Nhưng tôi không chắc điều đó chính xác hay cụ thể là nếu các đối tượng có tiền tố gạch dưới bị loại trừ. Ngoài ra, tôi phân tách rõ ràng hơn các phần về MODULES và BAO BÌ. Suy nghĩ của bạn?
Bob Stein

49

Từ (Tham khảo Python không chính thức) Wiki :

Tên công khai được xác định bởi một mô-đun được xác định bằng cách kiểm tra không gian tên của mô-đun cho một biến có tên __all__; nếu được định nghĩa, nó phải là một chuỗi các chuỗi được xác định hoặc nhập bởi mô-đun đó. Các tên được đưa vào __all__đều được coi là công khai và được yêu cầu tồn tại. Nếu __all__không được xác định, tập hợp các tên công khai bao gồm tất cả các tên được tìm thấy trong không gian tên của mô-đun không bắt đầu bằng ký tự gạch dưới ("_"). __all__phải chứa toàn bộ API công khai. Nó nhằm tránh vô tình xuất các mục không phải là một phần của API (chẳng hạn như các mô-đun thư viện đã được nhập và sử dụng trong mô-đun).


Các liên kết được liệt kê là chết. nhưng tìm thấy nguyên văn văn bản trên vdocument.net/ từ & tại đây: dokumen.tips/document/reference-567bab8d6118a.html
JayRizzo

8

__all__được sử dụng để ghi lại API công khai của mô-đun Python. Mặc dù nó là tùy chọn, __all__nên được sử dụng.

Đây là đoạn trích có liên quan từ tài liệu tham khảo ngôn ngữ Python :

Tên công khai được xác định bởi một mô-đun được xác định bằng cách kiểm tra không gian tên của mô-đun cho một biến có tên __all__; nếu được định nghĩa, nó phải là một chuỗi các chuỗi được xác định hoặc nhập bởi mô-đun đó. Các tên được đưa vào __all__đều được coi là công khai và được yêu cầu tồn tại. Nếu __all__không được xác định, nhóm tên công khai bao gồm tất cả các tên được tìm thấy trong không gian tên của mô-đun không bắt đầu bằng ký tự gạch dưới ('_'). __all__phải chứa toàn bộ API công khai. Nó nhằm tránh vô tình xuất các mục không phải là một phần của API (chẳng hạn như các mô-đun thư viện đã được nhập và sử dụng trong mô-đun).

PEP 8 sử dụng từ ngữ tương tự, mặc dù nó cũng cho thấy rõ rằng các tên đã nhập không phải là một phần của API công khai khi __all__vắng mặt:

Để hỗ trợ nội tâm tốt hơn, các mô-đun nên khai báo rõ ràng tên trong API công khai của chúng bằng __all__thuộc tính. Đặt __all__thành một danh sách trống cho biết mô-đun không có API công khai.

[...]

Tên nhập khẩu phải luôn luôn được coi là một chi tiết thực hiện. Các mô-đun khác không được dựa vào quyền truy cập gián tiếp vào các tên đã nhập như vậy trừ khi chúng là một phần được ghi lại rõ ràng trong API của mô-đun chứa, chẳng hạn như os.pathhoặc __init__mô-đun của gói hiển thị chức năng từ các mô hình con.

Hơn nữa, như được chỉ ra trong các câu trả lời khác, __all__được sử dụng để cho phép nhập ký tự đại diện cho các gói :

Câu lệnh nhập sử dụng quy ước sau: nếu __init__.pymã của gói xác định danh sách có tên __all__, thì nó được coi là danh sách tên mô-đun nên được nhập khi from package import *gặp phải.


8

Câu trả lời ngắn

__all__ảnh hưởng đến from <module> import *báo cáo.

Câu trả lời dài

Xem xét ví dụ này:

foo
├── bar.py
└── __init__.py

Trong foo/__init__.py:

  • (Ngụ ý) Nếu chúng tôi không xác định __all__, thì from foo import *sẽ chỉ nhập tên được xác định trong foo/__init__.py.

  • (Rõ ràng) Nếu chúng tôi xác định __all__ = [], sau đó from foo import *sẽ không nhập gì.

  • (Giải thích) Nếu chúng tôi xác định __all__ = [ <name1>, ... ], thì from foo import *sẽ chỉ nhập các tên đó.

Lưu ý rằng trong trường hợp ngầm, python sẽ không nhập tên bắt đầu bằng _. Tuy nhiên, bạn có thể buộc nhập tên như vậy bằng cách sử dụng __all__.

Bạn có thể xem tài liệu Python tại đây .


5

__all__ảnh hưởng đến cách làm from foo import *việc.

Mã nằm trong thân mô-đun (nhưng không phải trong thân hàm hoặc lớp) có thể sử dụng dấu hoa thị ( *) trong fromcâu lệnh:

from foo import *

Các *yêu cầu mà tất cả các thuộc tính của mô-đun foo(ngoại trừ các yêu cầu bắt đầu bằng dấu gạch dưới) được liên kết dưới dạng các biến toàn cục trong mô-đun nhập. Khi foocó một thuộc tính __all__, giá trị của thuộc tính là danh sách các tên bị ràng buộc bởi loại fromcâu lệnh này.

Nếu foolà một gói và nó __init__.pyđịnh nghĩa một danh sách có tên __all__, thì nó được coi là danh sách các tên mô hình con nên được nhập khi from foo import *gặp phải. Nếu __all__không được xác định, câu lệnh from foo import *nhập bất kỳ tên nào được xác định trong gói. Điều này bao gồm bất kỳ tên nào được xác định (và các mô hình con được tải rõ ràng) bởi __init__.py.

Lưu ý rằng __all__không phải là một danh sách. Theo tài liệu về importcâu lệnh , nếu được định nghĩa, __all__phải là một chuỗi các chuỗi được xác định hoặc nhập bởi mô-đun. Vì vậy, bạn cũng có thể sử dụng một tuple để lưu một số chu kỳ bộ nhớ và CPU. Chỉ cần đừng quên dấu phẩy trong trường hợp mô-đun xác định một tên công khai duy nhất:

__all__ = ('some_name',)

Xem thêm Tại sao nhập khẩu trên mạng *


1

Điều này được định nghĩa trong PEP8 ở đây :

Tên biến toàn cầu

(Chúng ta hãy hy vọng rằng các biến này chỉ được sử dụng trong một mô-đun.) Các quy ước tương tự như các biến cho các hàm.

Các mô-đun được thiết kế để sử dụng thông qua from M import *nên sử dụng __all__cơ chế để ngăn xuất khẩu toàn cầu hoặc sử dụng quy ước cũ hơn về tiền tố như vậy với dấu gạch dưới (mà bạn có thể muốn làm để chỉ ra các toàn cầu này là "mô-đun không công khai").

PEP8 cung cấp các quy ước mã hóa cho mã Python bao gồm thư viện chuẩn trong bản phân phối Python chính. Bạn càng làm theo điều này, bạn càng gần với mục đích ban đầu.

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.