本文转载自 https://zhuanlan.zhihu.com/p/115350758,并根据自己的理解整理,供学习记录使用,如有冒犯,请联系删除。
在Python工程里,当python检测到一个目录下存在__init__.py文件时,python就会把它当成一个模块(module)。Module跟C++的命名空间和Java的Package的概念很像,都是为了科学地组织化工程,管理命名空间。
init.py可以是一个空文件,也可以有非常丰富的内容。本文将举一个非常简单的例子,来介绍__init__.py的用法;在本文的最后,我将会再简单介绍__init__.py的设计理念。
在不利用__init__.py的情况下,我们来看一个四则运算的例子。我们的工程目录结构如下图所示:
如上图,其中,main.py是程序入口,我们用了不同的方式来import四则运算的各个子模块。arithmetic模块实现四则运算;为了展示需要,我们将加减乘除四种运算分别放在不同的代码中。
arithmetic下的每个文件的代码如下:
#
# @file add.py
#
def add(a, b):
return a + b
#
# @file dev.py
#
def dev(a, b):
return a / b
#
# @file mul.py
#
def mul(a, b):
return a * b
#
# @file sub.py
#
def sub(a, b):
return a - b
主函数main代码如下
#
# @file main.py
#
import arithmetic.add
import arithmetic.sub as sub
from arithmetic.mul import mul
from arithmetic import dev
def letscook(x, y, oper):
r = 0
if oper == "+":
r = arithmetic.add.add(x, y)
elif oper == "-":
r = sub.sub(x, y)
elif oper == "*":
r = mul(x, y)
else:
r = dev.dev(x, y)
print("{} {} {} = {}".format(x, oper, y, r))
x, y = 3, 8
letscook(x, y, "+")
letscook(x, y, "-")
letscook(x, y, "*")
letscook(x, y, "/")
从代码可以看出,为了使用arithmetic中的某个子模块(main.py中作者展示了四种不同的方式),我们必须使用非常繁琐的import语句;在使用的时候,也有可能需要使用非常繁琐的表达式。如果我们在不同的地方使用arithmetic的子模块,都需要写这么繁琐的import或者使用表达式,你可能会觉得心累。这就是为什么我们需要利用__init__.py来简化我们的使用。
还是第1小节中的工程目录结构,实现同样的功能,我们在__init__.py中编写了一些代码;同样,我们对main.py进行了一些适当的修改。
修改后__init__.py和main.py的代码如下:
#
# @file __init__.py
#
import arithmetic.add
import arithmetic.sub
import arithmetic.mul
import arithmetic.dev
add = arithmetic.add.add
sub = arithmetic.sub.sub
mul = arithmetic.mul.mul
dev = arithmetic.dev.dev
简化版的main_sim.py函数如下:
#
# @file main.py
#
import arithmetic as process
def letscook(x, y, oper):
r = 0
if oper == "+":
r = process.add(x, y)
elif oper == "-":
r = process.sub(x, y)
elif oper == "*":
r = process.mul(x, y)
else:
r = process.dev(x, y)
print("{} {} {} = {}".format(x, oper, y, r))
x, y = 3, 8
letscook(x, y, "+")
letscook(x, y, "-")
letscook(x, y, "*")
letscook(x, y, "/")
在__init__.py中, 我们import了arithmetic下的所有子模块,并在__init__.py中给各个子模块的核心功能取了新的名字,作为arithmetic模块的变量。所以我们在main.py中import了arithmetic模块之后,就可以直接进行使用了。如果你使用from arithmetic import * 语句,那么我们就可以使用add、sub、mul、dev,连process都省了。如下:
#
# @file main.py
#
from arithmetic import *
def letscook(x, y, oper):
r = 0
if oper == "+":
r = add(x, y)
elif oper == "-":
r = sub(x, y)
elif oper == "*":
r = mul(x, y)
else:
r = dev(x, y)
print("{} {} {} = {}".format(x, oper, y, r))
x, y = 3, 8
letscook(x, y, "+")
letscook(x, y, "-")
letscook(x, y, "*")
letscook(x, y, "/")
但是这种写法可能会跟某个文件的冲突,个人觉得有风险,还是按照上面的写法吧
init.py的原始使命是声明一个模块,所以它可以是一个空文件。在__init__.py中声明的所有类型和变量,就是其代表的模块的类型和变量,第2小节就是利用这个原理,为四则运算的4个子模块声明了新的变量。我们在利用__init__.py时,应该遵循如下几个原则: