Package内的__main__.py和__init__.py
2016-04-18 18:52
603 查看
假设一个最简单的Package如下:
如果你希望 python 将一个文件夹作为 Package 对待,那么这个文件夹中必须包含一个名为 __init__.py 的文件,即使它是空的。 参见:
Packages
如果你需要 python 将一个文件夹作为 Package 执行,那么这个文件夹中必须包含一个名为 __main__.py 的文件。参见: __main__ — Top-level script environment
在实际中,可以将pkg作为一个文件夹执行:
也可以将pkg作为一个Package执行:
那么,这两者有什么区别呢?为此,我们做一个简单的实验。
在__init__.py写入如下内容:
在__main__.py写入如下内容:
执行 python pkg 和 python -m pkg,对比一下它们的输出结果:
可以看出:
当作文件夹执行的时候,__init__.py 不会被执行。对于 __main__.py 来说,变量 __package__ 是一个空字符串。
当作模块执行的时候,会先执行 __init__.py ,再执行 __main__.py 。对于 __main__.py 来说,变量 __package__ 是 Package 的名字。另外, __init__.py 和 __main__.py 中的 __name__变量的值是不同的。
对于一个 Package 来说,既然 __init__.py 必须存在,并且当作为模块执行的时候,它会先执行,我们就应该把入口函数 main() 定义在 __init__.py 中。
当我们使用模块方式 -m 执行的时候, __init__.py 定义了 main() 函数,然后在 __main__.py 中调用它,就能实现我们统一入口的目的。
对 __init__.py 做如下修改:
对 __main__.py 做如下修改:
执行 python pkg ,调用失败;执行 python -m pkg,调用正常。对比一下它们的输出结果:
原因在于,sys.path 的第一个搜索路径,一个是 pkg ,一个是空字符串。
对于 python -m pkg 的调用方式来说,由于 __init__.py 被事先载入,此时 python 解释器已经知道了这是一个 package ,因此当前路径(空字符串)被包含在 sys.path 中。然后再调用 __main__.py ,这时 import pkg 这个包就没有问题了。
而对于 python hhlb 的调用方式来说,由于 __init__.py 没有被载入,python 解释器并不知道自己正在一个 Package 下面工作。默认的,python 解释器将 __main__.py 的当前路径 pkg 加入 sys.path 中,然后在这个路径下面寻找 pkg 这个模块。显然, pkg 文件夹下面并没有 pkg 这个模块,因此出错。
要理解这点,就要明白 __init__.py 是 python 解释器将当前文件夹作为 Package 处理的必要条件。如果没有读取到 __init__.py ,python 就不会认为当前的文件夹是一个 Package,而只是把它当作普通文件夹来处理。
既然找到了问题原因,那么只需要把当前路径加入到 sys.path 中,就能解决这个问题。
修改后的 __main__.py 如下:
执行 python pkg ,结果正常:
看到这里,有人可能会提出两个问题:
1. 为什么不直接在 sys.path 前面加上一个空字符串来解决问题呢?
答:因为,如果不是在当前路径下调用,空字符串就没效果了,比如执行 python /path/to/pkg。
2. 为什么不用 if __package__ == '' 来判断 __package__ 的值呢?
答:这并不是偷懒。因为可能会出现这种调用(不推荐): python pkg/__main__.py 。而这种情况下, __package__ 的值就是 None 而不是 '' 了。
├──pkg │ ├── __init__.py │ ├── __main__.py
如果你希望 python 将一个文件夹作为 Package 对待,那么这个文件夹中必须包含一个名为 __init__.py 的文件,即使它是空的。 参见:
Packages
如果你需要 python 将一个文件夹作为 Package 执行,那么这个文件夹中必须包含一个名为 __main__.py 的文件。参见: __main__ — Top-level script environment
在实际中,可以将pkg作为一个文件夹执行:
python pkg
也可以将pkg作为一个Package执行:
python -m pkg
那么,这两者有什么区别呢?为此,我们做一个简单的实验。
在__init__.py写入如下内容:
#!/usr/bin/env python import sys print('__init__') print('__init__.__name__', __name__) print('__init__.__package__', __package__)
在__main__.py写入如下内容:
#!/usr/bin/env python import sys print('__main__') print('__main__.__name__', __name__) print('__main__.__package__', __package__) print('sys.path', sys.path)
执行 python pkg 和 python -m pkg,对比一下它们的输出结果:
可以看出:
当作文件夹执行的时候,__init__.py 不会被执行。对于 __main__.py 来说,变量 __package__ 是一个空字符串。
当作模块执行的时候,会先执行 __init__.py ,再执行 __main__.py 。对于 __main__.py 来说,变量 __package__ 是 Package 的名字。另外, __init__.py 和 __main__.py 中的 __name__变量的值是不同的。
对于一个 Package 来说,既然 __init__.py 必须存在,并且当作为模块执行的时候,它会先执行,我们就应该把入口函数 main() 定义在 __init__.py 中。
当我们使用模块方式 -m 执行的时候, __init__.py 定义了 main() 函数,然后在 __main__.py 中调用它,就能实现我们统一入口的目的。
对 __init__.py 做如下修改:
#!/usr/bin/env python import sys print('__init__') print('__init__.__name__', __name__) print('__init__.__package__', __package__)
print('sys.path', sys.path)
def main():
print('__init__.main()')
对 __main__.py 做如下修改:
#!/usr/bin/env python import sys print('__main__') print('__main__.__name__', __name__) print('__main__.__package__', __package__) print('sys.path', sys.path)
import pkg
pkg.main()
执行 python pkg ,调用失败;执行 python -m pkg,调用正常。对比一下它们的输出结果:
原因在于,sys.path 的第一个搜索路径,一个是 pkg ,一个是空字符串。
对于 python -m pkg 的调用方式来说,由于 __init__.py 被事先载入,此时 python 解释器已经知道了这是一个 package ,因此当前路径(空字符串)被包含在 sys.path 中。然后再调用 __main__.py ,这时 import pkg 这个包就没有问题了。
而对于 python hhlb 的调用方式来说,由于 __init__.py 没有被载入,python 解释器并不知道自己正在一个 Package 下面工作。默认的,python 解释器将 __main__.py 的当前路径 pkg 加入 sys.path 中,然后在这个路径下面寻找 pkg 这个模块。显然, pkg 文件夹下面并没有 pkg 这个模块,因此出错。
要理解这点,就要明白 __init__.py 是 python 解释器将当前文件夹作为 Package 处理的必要条件。如果没有读取到 __init__.py ,python 就不会认为当前的文件夹是一个 Package,而只是把它当作普通文件夹来处理。
既然找到了问题原因,那么只需要把当前路径加入到 sys.path 中,就能解决这个问题。
修改后的 __main__.py 如下:
#!/usr/bin/env python import os, sys print('__main__') print('__main__.__name__', __name__) print('__main__.__package__', __package__) if not __package__: path = os.path.join(os.path.dirname(__file__), os.pardir) sys.path.insert(0, path) print('sys.path', sys.path) import pkg pkg.main()
执行 python pkg ,结果正常:
看到这里,有人可能会提出两个问题:
1. 为什么不直接在 sys.path 前面加上一个空字符串来解决问题呢?
答:因为,如果不是在当前路径下调用,空字符串就没效果了,比如执行 python /path/to/pkg。
2. 为什么不用 if __package__ == '' 来判断 __package__ 的值呢?
答:这并不是偷懒。因为可能会出现这种调用(不推荐): python pkg/__main__.py 。而这种情况下, __package__ 的值就是 None 而不是 '' 了。
相关文章推荐
- 定时管理器框架-Task.MainForm
- The Longest Straight(FZU2216)
- saiku执行速度优化二
- UltraISO制作启动盘及提取U盘为ISO镜像
- shrio 权限管理filterChainDefinitions过滤器配置
- 切图教程,PS和AI切图方法分享
- error LNK2005: _DllMain@12 already defined 错误解决方案
- 人工智能60年:图灵的在天之灵,安息吧!
- 【翻译】GCJ 2008 APAC local onsites C Millionaire 题解
- main()函数的两个参数
- Implicit & Explicit Waits in Selenium
- Conversion to Dalvik format failed with error 1
- explain分析查询
- Map.containsKey(String key)
- tail -f 不好用? 用法小解析
- 人工智能60年:人工智能音乐即将问世
- 17、责任链模式(ChainofResponsibility)
- 错误:HTTP load failed (kCFStreamErrorDomainSSL, -9813)/Error Domain=NSURLErrorDomain Code=-1202
- 关于curl: (2) Failed Initialization
- XP系统通过Twain扫描提示成像设备无法初始化的解决方法