Как всегда в Python, __all__
является скорее руководством, чем правилом.Это происходит из-за того, что мы любим-ненавидим *-import
, описанные в документах как
Если список идентификаторов заменяется звездочкой ('*'), все публичные имена, определенные в модуле, связаны в локальном пространстве имен оператора import
.
Здесь возникает непосредственная техническая трудность: как интерпретатору знать, что такое публичнаяимена модуля есть?Существует соглашение, что любое имя в модуле, не начинающееся с _
, является открытым;Вы можете подумать, что в первом приближении нужно просто импортировать все такие имена в пространство имен модуля.К сожалению, это становится более сложным, когда вы представляете пакеты, потому что тогда вычисление открытых имен становится большой задачей, включающей различные операции импорта, переписывания путей, чтения файлов и что у вас есть.Это не хорошая вещь.Таким образом, было принято упрощающее решение, позволяющее автору модуля точно указать, какие имена в пакете следует импортировать из * -импорта, определив __all__
в модуле.
Но если вы этого не сделаете* -import - если вы дадите интерпретатору имя переменной, которую вы хотите импортировать, - ему не нужно беспокоиться о поиске всех глобальных имен, поэтому он может игнорировать __all__
и просто искать имя впространство имен модуля.
Это означает, что __all__
может не совпадать с подмножеством locals().keys()
, не начинающимся с подчеркивания.В частности, в модуле могут быть совершенно хорошие объекты, которые не экспортируются * -импортами.Вот что происходит с NO_DEFAULT
.