我有一个小包,它有一些依赖项,例如 pandas 和 gensim。文件结构是这样的
/package
__init__.py
agg_clean.py
Run Code Online (Sandbox Code Playgroud)
在__init__.py文件中,我有import agg_clean所以我能够以链接的方式访问这些功能,例如:
import package as pkg
pkg.agg_clean.function()
Run Code Online (Sandbox Code Playgroud)
但是,我在agg_clean.py,(pandas、os 等)中有几个导入语句。当我像上面那样进行链式导入时,我也可以访问 中的导入agg_clean,例如pkg.agg_clean.os.listdir()
如何在包导入中隐藏各种模块的导入?
tl;dr:你不能干净利落。或者更准确地说,你不应该担心这样的事情。
namespace collisions在这种情况下没有,因为 os 模块是在 then name 下加载的pkg.agg_clean.os。如果用户想使用您导入的 os 包,让他们这样做没有坏处。最重要的是,没有什么好方法可以阻止他们这样做。
这里有一些有趣的事情要记住。取以下可以被另一个python脚本导入的python模块:
# module_im_importing.py
import os as _os
__all__ = ["echo"]
name_not_available = 'some_constant_string'
def echo(object):
pass
Run Code Online (Sandbox Code Playgroud)
如果您的用户使用 导入裸模块import module_im_importing,则所有定义的变量都可以在名称下用于其环境module_im_importing。
>>> import module_im_importing
>>> dir() # Lookup local namespace
['__builtins__', '__doc__', '__name__', '__package__', 'module_im_importing']
>>> dir(module_im_importing) # See defined items in your package.
['__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'echo', 'name_not_available', 'os']
Run Code Online (Sandbox Code Playgroud)
如果他们改为from module_im_importing import * (这是不鼓励的),则行为会有所不同:
>>> from module_im_importing import *
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'echo']
Run Code Online (Sandbox Code Playgroud)
这会导致文件中定义的名称module_im_importing.py被导入到用户的本地命名空间中。因为我们__all__在您的模块中使用了,所以只有在您的模块中定义的项目__all__才会导入到用户本地命名空间中。例如,如果您定义了一个echo与他们可能正在使用的另一个包冲突的函数,这可能会污染他们的命名空间。
这就是为什么在PEP8中显然不赞成通配符导入的原因。从文件:
Wildcard imports (from <module> import *) should be avoided, as they make it unclear which names are present in the namespace, confusing both readers and many automated tools.
无论如何,请不要为这样的事情担心。如果您的模块的用户不遵循 PEP8,这只是一个问题,并且无论如何都应该向他们展示他们的方式的错误。请记住,在 Python 中,We're all consenting adults here.