0. 标题
Python专家编程系列: 12.Python包(package)中__init__.py的作用
id: 101
作者: quantgalaxy@outlook.com
欢迎交流
1. 什么是包(package)中的 __init__.py 文件
假设你有一个Python目录,里面有一堆Python文件,你想把它当作一个包来对待。只要在里面放一个 __init__.py 文件就行了。
Python会将该目录识别为一个包。这就像代码和Python之间的秘密握手。
__init__.py 文件可以是一个空文件。
如果你需要有些特殊的处理,也可以在里面写上一些代码。
当其他人想要使用你的包时,他们将它导入到他们的代码中,Python首先会去寻找那个神奇的 __init__.py,把它加载起来。
如果没有__init__.py, Python将无法将目录识别为包,并且您将无法使用标准的" import "语句从其中导入模块。
在旧版本的Python(3.3之前)中,必须在包中创建__init__.py文件,然后才能使用from mypackage import mymodule形式的import语句。
自3.3版和PEP 420实现以来,Python将在许多情况下隐式自动创建“命名空间包”。
这意味着__\init__.py现在通常是可选的,但它仍然有助于构建初始化代码并定义像from mypackage import *这样的语句应该如何工作。
2. __init__.py 是如何帮助创建包的
__init__.py允许您将代码组织成模块化块,使所有内容都具有超级可管理性和可重用性。
把它想象成你包的蓝图——你可以在 __init__.py中定义通用函数、变量,甚至导入其他模块,为你的包的功能建立基础。
举例看下:
让我们创建一个名为my_package的简单包来说明 __init__.py如何在my_package目录中工作。
创建一个名为__init__.py的空文件,并创建另一个名为greetings.py的文件,并编写一个名为say_hello()的函数,该函数打印“Hello, World!”
# greetings.py
def say_hello():
print("Hello, World!")
现在,可以从my_package目录之外的任何文件导入问候模块并使用say_hello()函数。这将打印“Hello, World!”。
因为 __init__.py 使 greetings 模块可以从 my_package 命名空间中访问。
from my_package import greetings
greetings.say_hello()
# Hello, World!
更大和更复杂的包通常使用__init__.py来更好地组织代码,并运行在导入包时应该自动运行的任何初始化。
例如,您可以在 xx/__init__.py文件中添加print行(“Hi from __init__.py”)。现在,如果你导入包,它会立即运行print语句。
3. __init__.py 对 __all__ 的影响
__init__.py中定义的一个常见的东西是 __all__变量。
当用户在程序中运行导入语句时,将覆盖当用户以 “from mypackage import *”" 的形式运行import语句时应该导入的模块和函数。
默认情况下,Python不会从包中导入模块。因此,如果我们更改calculator.py文件中的第一行,从操作中导入所有内容,它将无法工作。
假设我们有一个operations包。
目录布局如下:
├── calculator.py
└── operations
├── divider.py
└── multiplier.py
文件里面的实现如下:
divider.py
# operations/divider.py
class Divider:
def divide(self, a, b):
return a / b
multiplier.py
# operations/multiplier.py
class Multiplier:
def multiply(self, a, b):
return a * b
calculator.py
# calculator.py
# broken import unless we explicitly define `__all__` in `__init__.py`
from operations import *
mymultiplier = multiplier.Multiplier()
result = mymultiplier.multiply(2, 5)
print(f"2 x 5 is {result}")
mydivider = divider.Divider()
result = mydivider.divide(10, 2)
print(f"10 / 2 is {result}")
如果运行 calculator.py 文件,会触发一个错误:
Traceback (most recent call last):
File "/Users/g/python_init_example/calculator.py", line 3, in <module>
mymultiplier = multiplier.Multiplier()
^^^^^^^^^^
NameError: name 'multiplier' is not defined
如果我们在 operations/init.py 中 添加一行:
__all__ = ['divider', 'multiplier']
上面的脚本就可以正常执行了:
2 x 5 is 10
10 / 2 is 5.0
__init__.py是创建结构化和有组织的Python包的基本构建块。
它就像一种无形的粘合剂,将您的代码粘合在一起,使其更容易管理重用和共享。
因此,简单来说,__init__.py就像是Python项目的起跑线。
4. 作者信息
作者: quantgalaxy@outlook.com
欢迎交流