파이썬을 점점 더 많이 사용하고 __all__
있으며 다른 __init__.py
파일에 변수 세트가 계속 표시 됩니다. 누군가 이것이 무엇을하는지 설명 할 수 있습니까?
답변
로 해석되는 해당 모듈의 공용 객체 목록입니다 import *
. 밑줄로 시작하는 모든 항목을 숨기는 기본값을 무시합니다.
답변
여기에 명시 적으로 언급되지 않은 링크는 정확히 언제 __all__
사용 되는지 입니다. 모듈에서 from <module> import *
사용될 때 어떤 심볼을 내보낼 지 정의하는 문자열 목록입니다 .
예를 들어, 다음 코드 foo.py
를 명시 적으로는 기호 수출 bar
과 baz
:
__all__ = ['bar', 'baz']
waz = 5
bar = 10
def baz(): return 'baz'
그런 다음이 기호를 다음과 같이 가져올 수 있습니다.
from foo import *
print(bar)
print(baz)
# The following will trigger an exception, as "waz" is not exported by the module
print(waz)
경우 __all__
위의이 주석의 기본 동작은,이 코드는 완료 될 때까지 실행됩니다 import *
주어진 공간에서, 밑줄로 시작하지 않는 모든 기호를 가져 오는 것입니다.
참조 : https://docs.python.org/tutorial/modules.html#importing-from-a-package
참고 : 동작에만 __all__
영향을줍니다 from <module> import *
. 언급되지 않은 멤버 __all__
는 여전히 모듈 외부에서 액세스 할 수 있으며로 가져올 수 있습니다 from <module> import <member>
.
답변
파이썬에서 __all__을 설명 하시겠습니까?
__all__
다른__init__.py
파일에 변수 세트가 계속 표시 됩니다.이것은 무엇을 하는가?
무엇을 __all__
합니까?
모듈에서 의미 적으로 “공용”이름을 선언합니다. 에 이름이 있으면 __all__
사용자 는 해당 이름 을 사용해야하며 변경되지 않을 것으로 기대할 수 있습니다.
또한 프로그래밍 방식으로 영향을 미칩니다.
import *
__all__
모듈에서, 예 module.py
:
__all__ = ['foo', 'Bar']
수단이 때 import *
모듈에서의의 이름 만이 __all__
가져올 수 있습니다 :
from module import * # imports foo and Bar
문서화 도구
문서 및 코드 자동 완성 도구는 __all__
모듈에서 사용 가능한 것으로 표시되는 이름을 결정하기 위해 실제로 검사해야 할 수도 있습니다.
__init__.py
디렉토리를 파이썬 패키지로 만든다
로부터 문서 :
__init__.py
파일은 파이썬 치료 패키지가 들어있는 같은 디렉토리를 만들기 위해 필요합니다; 이는 문자열과 같은 공통 이름을 가진 디렉토리가 나중에 모듈 검색 경로에서 발생하는 유효한 모듈을 실수로 숨기지 않도록하기 위해 수행됩니다.가장 간단한 경우
__init__.py
빈 파일 일 수 있지만 패키지의 초기화 코드를 실행하거나__all__
변수를 설정할 수도 있습니다.
그래서이 __init__.py
을 선언 할 수 있습니다 __all__
A의 패키지 .
API 관리
패키지는 일반적으로 서로 가져올 수 있지만 반드시 __init__.py
파일 과 함께 묶인 모듈로 구성 됩니다. 이 파일은 디렉토리를 실제 파이썬 패키지로 만듭니다. 예를 들어, 패키지에 다음 파일이 있다고 가정하십시오.
package
├── __init__.py
├── module_1.py
└── module_2.py
파이썬으로이 파일들을 만들어 보도록하겠습니다. 다음을 파이썬 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
""")
이제 다른 사람이 패키지를 가져올 때 사용할 수있는 완전한 API를 제시했습니다.
import package
package.foo()
package.Bar()
그리고 패키지에는 package
네임 스페이스를 어지럽히는 모듈을 만들 때 사용한 다른 구현 세부 정보가 모두 없습니다 .
__all__
에 __init__.py
더 많은 작업을 한 후에는 모듈이 너무 커서 (수천 줄과 같이) 분할해야한다고 결정했을 수 있습니다. 따라서 다음을 수행하십시오.
package
├── __init__.py
├── module_1
│ ├── foo_implementation.py
│ └── __init__.py
└── module_2
├── Bar_implementation.py
└── __init__.py
먼저 모듈과 동일한 이름으로 서브 패키지 디렉토리를 만드십시오.
subpackage_1 = package / 'module_1'
subpackage_1.mkdir()
subpackage_2 = package / 'module_2'
subpackage_2.mkdir()
구현을 이동하십시오.
package_module_1.rename(subpackage_1 / 'foo_implementation.py')
package_module_2.rename(subpackage_2 / 'Bar_implementation.py')
각각에 대해 __init__.py
선언하는 서브 패키지에 대해 s를 작성 하십시오 __all__
.
(subpackage_1 / '__init__.py').write_text("""
from .foo_implementation import *
__all__ = ['foo']
""")
(subpackage_2 / '__init__.py').write_text("""
from .Bar_implementation import *
__all__ = ['Bar']
""")
그리고 지금 당신은 여전히 패키지 수준에서 API를 프로비저닝했습니다.
>>> import package
>>> package.foo()
>>> package.Bar()
<package.module_2.Bar_implementation.Bar object at 0x7f0c2349d210>
또한 서브 패키지의 모듈 레벨 대신 서브 패키지 레벨에서 관리 할 수있는 것을 API에 쉽게 추가 할 수 있습니다. API에 새 이름을 추가하려면 간단히 __init__.py
예를 들어 module_2에서을 업데이트하십시오 .
from .Bar_implementation import *
from .Baz_implementation import *
__all__ = ['Bar', 'Baz']
Baz
최상위 API 로 게시 할 준비가되지 않은 경우 최상위 레벨에서 다음을 수행 __init__.py
할 수 있습니다.
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
사용자가의 가용성을 알고 있으면 다음 Baz
을 사용할 수 있습니다.
import package
package.Baz()
그러나 그들이 그것에 대해 모른다면 다른 도구 ( pydoc 같은 )는 그들에게 알리지 않을 것입니다.
나중에 Baz
프라임 타임 준비가 완료 되면 변경할 수 있습니다 .
from .module_1 import *
from .module_2 import *
__all__ = ['foo', 'Bar', 'Baz']
접두사 _
대 __all__
:
기본적으로 Python은로 시작하지 않는 모든 이름을 내 보냅니다 _
. 확실히이 메커니즘에 의존 할 수 있습니다. 파이썬 표준 라이브러리의 일부 패키지는, 사실, 할 이에 의존하지만, 예를 들어, 자신의 수입 별명 그래서 그들은을 위해 ctypes/__init__.py
:
import os as _os, sys as _sys
이 _
규칙을 사용하면 이름을 다시 지정하는 중복성이 제거되므로 더 우아 할 수 있습니다. 그러나 수입에 대한 중복성을 추가하고 (많은 수입이있는 경우) 이 일관된 작업을 잊어 버리기 쉽습니다 . 마지막으로 원하는 것은 구현 세부 사항 만 의도 한 것을 무기한으로 지원해야합니다. _
함수 이름 을 지정할 때 접두사를 잊어 버렸기 때문 입니다.
나는 __all__
내 코드를 사용하는 다른 사람들이 사용하고 사용하지 않아야 할 것을 알 수 있도록 개발 라이프 사이클 초기에 모듈에 대한 초기 글을 씁니다 .
표준 라이브러리에있는 대부분의 패키지도 사용 __all__
합니다.
피하면 __all__
차종의 의미
다음 _
대신에 접두사 규칙 을 따르는 것이 합리적 입니다 __all__
.
- 아직 초기 개발 모드에 있으며 사용자가 없으며 지속적으로 API를 조정하고 있습니다.
- 어쩌면 사용자가 있지만 API를 다루는 단위 테스트가 있으며 여전히 API에 적극적으로 추가하고 개발을 조정하고 있습니다.
export
장식
사용의 단점은 __all__
두 번 내보내는 함수 및 클래스 이름을 작성해야하며 정보는 정의와 별도로 유지된다는 것입니다. 우리는 수 이 문제를 해결하기 위해 장식을 사용합니다.
나는 David Beazley의 포장에 관한 이야기에서 그런 수출 데코레이터에 대한 아이디어를 얻었다. 이 구현은 CPython의 기존 수입 업체에서 잘 작동하는 것 같습니다. 특별한 가져 오기 후크 또는 시스템이있는 경우 보증하지 않지만이를 채택하는 경우에는 취소하기가 쉽지 않습니다. 이름을 수동으로 다시 추가하면됩니다.__all__
예를 들어 유틸리티 라이브러리에서 데코레이터를 정의합니다.
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
그런 다음을 정의하는 위치 __all__
에서 다음을 수행하십시오.
$ 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()
그리고 이것은 메인으로 실행되거나 다른 기능으로 가져 오더라도 잘 작동합니다.
$ cat > run.py
import main
main.main()
$ python run.py
main
API 프로비저닝 import *
도 작동합니다.
$ 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
답변
나는 이것을 정확하게 추가하고 있습니다.
다른 모든 답변은 모듈을 나타 냅니다. 파일에 명시 적으로 언급 __all__
된 원래 질문 __init__.py
이므로 파이썬 패키지 에 관한 것 입니다.
일반적으로 명세서 __all__
의 from xxx import *
변형 import
이 사용될 때만 작동합니다 . 이것은 패키지뿐만 아니라 모듈에도 적용됩니다.
모듈의 동작은 다른 답변에 설명되어 있습니다. 패키지의 정확한 동작은 여기 에 자세히 설명되어 있습니다 .
간단히 말해서 __all__
패키지 레벨에서 모듈 내에서 이름 을 지정하는 것과 달리 패키지 내 모듈 을 처리한다는 점을 제외하면 모듈과 거의 동일합니다 . 따라서 __all__
우리가 사용할 때 현재 네임 스페이스로로드 및 임포트 될 모든 모듈을 지정합니다 from package import *
.
가장 큰 차이점은 패키지에서 의 선언 을 생략 하면 명령문 이 아무것도 가져 오지 않는다는 것입니다 (문서에 설명 된 예외는 위의 링크 참조).__all__
__init__.py
from package import *
반면에 __all__
모듈에서 생략 하면 “별표 가져 오기”는 모듈에 정의 된 모든 이름 (밑줄로 시작하지 않음)을 가져옵니다.
답변
또한 pydoc이 표시 할 내용을 변경합니다.
module1.py
a = "A"
b = "B"
c = "C"
module2.py
__all__ = ['a', 'b']
a = "A"
b = "B"
c = "C"
pydoc 모듈 1
모듈 module1에 대한 도움말 : 이름 모듈 1 파일 module1.py DATA = 'A' , B = 'B' C = 'C'
pydoc 모듈 2
모듈 module2에 대한 도움말 : 이름 모듈 2 파일 module2.py DATA __all__ = 'A', 'B'] = 'A' , B = 'B'
나는 __all__
내 모든 세부 사항뿐만 아니라 밑줄 내부 세부 사항을 선언 합니다. 이것은 실시간 통역 세션에서 전에 사용하지 않은 것을 사용할 때 실제로 도움이됩니다.
답변
__all__
사용자 정의 *
에from <module> import *
__all__
사용자 정의 *
에from <package> import *
모듈 A는 .py
가져올 수 의미 파일.
패키지는 기호가있는 디렉토리 __init__.py
파일입니다. 패키지는 일반적으로 모듈을 포함합니다.
모듈
""" cheese.py - an example module """
__all__ = ['swiss', 'cheddar']
swiss = 4.99
cheddar = 3.99
gouda = 10.99
__all__
인간에게 모듈 의 “공개”기능을 알려줍니다 . [ @AaronHall ] 또한 pydoc 은이를 인식합니다. [ @ 롱 포크 ]
에서 모듈 가져 오기 *
방법 swiss
과 cheddar
로컬 네임 스페이스로 가져 오는 방법을 참조하십시오 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
이 없으면 __all__
밑줄로 시작하지 않는 모든 기호를 사용할 수 있습니다.
없는 수입품 *
은__all__
가져 오기 모듈
>>> import cheese
>>> cheese.swiss, cheese.cheddar, cheese.gouda
(4.99, 3.99, 10.99)
에서 모듈 수입 이름
>>> from cheese import swiss, cheddar, gouda
>>> swiss, cheddar, gouda
(4.99, 3.99, 10.99)
수입 모듈 등 의 localName
>>> import cheese as ch
>>> ch.swiss, ch.cheddar, ch.gouda
(4.99, 3.99, 10.99)
패키지
에서 __init__.py
의 파일 패키지 __all__
공공 모듈 또는 다른 개체의 이름을 가진 문자열의 목록입니다. 이러한 기능은 와일드 카드 가져 오기에 사용할 수 있습니다. 모듈과 마찬가지로 패키지에서 와일드 카드를 가져올 때 __all__
사용자 정의합니다 *
. [ @MartinStettner ]
다음은 Python MySQL 커넥터 에서 발췌 한 내용입니다 __init__.py
.
__all__ = [
'MySQLConnection', 'Connect', 'custom_error_exception',
# Some useful constants
'FieldType', 'FieldFlag', 'ClientFlag', 'CharacterSet', 'RefreshOption',
'HAVE_CEXT',
# Error handling
'Error', 'Warning',
...etc...
]
패키지의 경우 별표가없는 별표 인__all__
기본 경우 는 복잡합니다. 파일 시스템을 사용하여 패키지의 모든 모듈을 검색하려면 파일 시스템을 사용하는 것이 비용이 많이 들기 때문입니다. 대신 문서를 읽을 때 정의 된 객체 만 __init__.py
가져 옵니다 .
경우
__all__
정의되지 않은, 문은from sound.effects import *
않습니다 하지 패키지의 모든 서브 모듈 가져sound.effects
현재 네임 스페이스로를; 패키지sound.effects
를 가져 왔는지 확인하고 (초기화 코드를 실행 중일 수 있음__init__.py
) 패키지에 정의 된 이름을 가져옵니다. 여기에는에 의해 정의 된 (및 명시 적으로로드 된 하위 모듈) 이름이 포함됩니다__init__.py
. 또한 이전 import 문으로 명시 적으로로드 된 패키지의 하위 모듈도 포함합니다.
와일드 카드 가져 오기는 독자와 많은 자동화 도구를 혼동하기 때문에 피해야합니다.
[ PEP 8 , @ToolmakerSteve]
답변
에서 (비공식) 파이썬 레퍼런스 위키 :
모듈이 정의한 공개 이름은 모듈의 네임 스페이스를 변수 이름으로 확인하여 결정됩니다
__all__
. 정의 된 경우 해당 모듈에서 정의하거나 가져온 이름 인 일련의 문자열이어야합니다. 이름__all__
은 모두 공개로 간주되며 존재해야합니다.__all__
이 정의되지 않은 경우 공개 이름 세트에는 밑줄 문자 ( “_”)로 시작하지 않는 모듈 네임 스페이스에있는 모든 이름이 포함됩니다.__all__
전체 공개 API를 포함해야합니다. API에 포함되지 않은 항목 (예 : 모듈 내에서 가져 와서 사용 된 라이브러리 모듈)을 실수로 내 보내지 않도록합니다.