Python: __all__
Effective Python Item 50: Use Packages to Organize Modules and Provide Stable APIs
Python can limit the “interface” exposed to API consumers who use import * by defining the __all__ special attribute of a module or package.
~~~~~ 2017-11-16 补充开始 ~~~~~
Karol Kuczmarski: __all__ and wild imports in Python:
__all__doesn’t prevent any of the module symbols (functions, classes, etc.) from being directly imported. In our the example, the seemingly omittedbazfunction (which is not included in__all__), is still perfectly importable by writingfrom module import baz.
Similarly,__all__doesn’t influence what symbols are included in the results ofdir(module)orvars(module). So in the case above, adircall would result in a['Foo', 'bar', 'baz']list, even though'baz'does not occur in__all__.
In other words, the content of__all__is more of a convention rather than a strict limitation. Regardless of what you put there, every symbol defined in your module will still be accessible from the outside.
This is a clear reflection of the common policy in Python: assume everyone is a consenting adult, and that visibility controls are not necessary.
~~~~~ 2017-11-16 补充结束 ~~~~~
Define __all__ in a module
When consuming code does from foo import *, only the attributes in foo.__all__ will be imported from foo. If __all__ isn’t present in foo, then only public attributes, those without a leading underscore, are imported.
# foo.py
__all__ = ['Foo']
class Foo(object):
pass
Define __all__ for a package
To do this with package mypackage, you need to modify the __init__.py file in the mypackage directory. This file actually becomes the contents of the mypackage module when it’s imported. Thus, you can specify an explicit API for mypackage by limiting what you import into __init__.py.
Suppose mypackage directory structure is:
mypackage
├── __init__.py
├── model.py
└── util.py
and __all__ are defined in model.py and util.py both.
Since all of my internal modules already specify __all__, I can expose the public interface of mypackage by simply importing everything from the internal modules and updating __all__ accordingly.
# __init__.py
__all__ = []
from .models import *
__all__ += models.__all__
from .utils import *
__all__ += utils.__all__
Note that from .xxx (no space between . and xxx) means relative import, i.e. importing from a relative path.
PEP 328 – Imports: Multi-Line and Absolute/Relative (Guido’s Decision):
Guido has Pronounced that relative imports will use leading dots. A single leading dot indicates a relative import, starting with the current package. Two or more leading dots give a relative import to the parent(s) of the current package, one level per dot after the first.
Also note that you can also from . import xxx to relatively import the whole module xxx.
留下评论