使用__all__
结合from 模块名 import *
可以帮助你控制对外公开的API,防止不必要的成员被暴露。
Python模块__all__
变量示例
第一步:创建项目结构
首先,你需要在你的计算机上建立一个工作目录,并在这个目录下创建几个文件。这些文件将代表我们的不同模块。这里是一个简单的示例结构:
fish_project/
│
├── main.py
├── fish_data.py
└── fishing_tools.py
main.py
是主程序入口。fish_data.py
将包含一些数据和函数,用于处理关于鱼的信息。fishing_tools.py
将提供一些工具函数,帮助我们更有效地“捕鱼”。
第二步:编写fish_data.py
模块
接下来,我们在fish_data.py
中定义一些基本的数据和函数。这个模块将模拟一个鱼类数据库,并提供查询功能。
# fish_data.py
def chaxun_yu_mingcheng(yu_id):
"""根据鱼的ID查询鱼的名字"""
yu_zidian = {
1: '鲤鱼',
2: '草鱼',
3: '鲫鱼'
}
return yu_zidian.get(yu_id, '未知鱼种')
def jisuan_yu_zhonglei_shuliang():
"""计算鱼类种类数量"""
return len(chaxun_yu_mingcheng.__globals__.get('yu_zidian', {}))
# 这里我们定义了 __all__ 来指定当其他模块从当前模块导入*时,可以使用的名称
__all__ = ['chaxun_yu_mingcheng']
注意,在上面的例子中,我们通过__all__
列表指定了只有chaxun_yu_mingcheng
函数可以在使用from fish_data import *
时被直接访问到。这意味着jisuan_yu_zhonglei_shuliang
不会被导入,除非明确地指定它。
第三步:编写fishing_tools.py
模块
现在,让我们为项目添加一些有用的工具。fishing_tools.py
可能包括一些辅助函数,比如格式化输出或数据转换等。
# fishing_tools.py
def da_yin_jieshao(xinxi):
"""打印一条信息,附带装饰性的边框"""
print('=' * 40)
print(xinxi.center(40))
print('=' * 40)
# 同样,我们也设置了 __all__ 列表
__all__ = ['da_yin_jieshao']
第四步:整合所有内容于main.py
最后,我们需要在main.py
中整合所有的代码片段。这将作为整个项目的起点,同时也是展示__all__
作用的地方。
# main.py
# 导入必要的模块
from fish_data import *
import fishing_tools as ft
# 使用fish_data模块提供的功能
print("查询ID为2的鱼名:")
print(chaxun_yu_mingcheng(2)) # 应该输出: 草鱼
# 注意,尝试调用未被导出的函数会引发NameError
# print(jisuan_yu_zhonglei_shuliang()) # 如果取消注释,会导致错误
# 使用fishing_tools模块的功能
ft.da_yin_jieshao('欢迎来到山海摸鱼人的世界!')
通过上述例子,你可以看到__all__
是如何控制哪些名字可以被外部直接访问的。这种方式有助于保持接口清晰,并且避免了命名冲突的问题。
Python 模块导入注意事项
以下是关于__all__
变量及不同导入方法的关键注意事项:
1、使用 from 模块名 import *
导入:
当一个模块定义了 __all__
列表,并且你使用from 模块名 import *
的形式来导入这个模块时,只有__all__
列表中明确列出的成员会被导入。任何未在 __all__
列表中指定的成员将不会被导入到当前命名空间。这意味着即使模块内存在这些成员,它们也不会自动出现在你的代码中。这种做法有助于限制从外部访问的接口,减少命名冲突的可能性,并且可以提高代码的安全性和清晰度。
2、使用 import 模块名
导入:
通过这种方式导入模块后,你可以通过模块名前缀(或别名)来访问模块内的所有非私有成员。例如,如果模块名为 fish_data
,你可以通过fish_data.成员名
的方式访问其内部函数或变量。私有成员(即以单下划线 _
开头的名称)通常被认为是仅供模块内部使用的,不应直接从外部访问。虽然技术上仍然可以通过这种形式访问,但这样做是不推荐的,因为它违背了设计意图。使用完整的模块名作为前缀可以帮助避免命名冲突,并且使得代码更加易于理解。
3、使用 from 模块名 import 成员
导入:
这种方式允许你直接导入并使用特定的成员,而不需要通过模块名作为前缀。例如, from fish_data import chaxun_yu_mingcheng
可以直接让你使用chaxun_yu_mingcheng
函数。即使模块中设置了 __all__
列表,当你明确指定了要导入的成员时,__all__
设置将不起作用。也就是说,无论该成员是否列在__all__
中,都可以成功导入。这种导入方式可以使代码更简洁,但如果过度使用,可能会导致命名空间污染和潜在的命名冲突问题。因此,建议谨慎选择要直接导入的成员。