三、主模块和非主模块
1、主模块和非主模块的定义
在 Python 函数中,如果一个函数调用了其他函数完成一项功能,我们称这个函数为主函数,如果一个函数没有调用其他函数,我们称这种函数为非主函数。主模块和非主模块的定义也类似,如果一个模块被直接使用,而没有被别人调用,我们称这个模块为主模块,如果一个模块被别人调用,我们称这个模块为非主模块。
2、name 属性
在 Python 中,有主模块和非主模块之分,当然,我们也得区分他们啊。那么怎么区分主模块和非主模块呢?
这就需要用到 __name__
属性了,这个 ——name——
属性值是一个变量,且这个变量是系统给出的。利用这个变量可以判断一个模块是否是主模块。如果一个属性的值是 __main__
,那么就说明这个模块是主模块,反之亦然。但是要注意了:** 这个 __main__
属性只是帮助我们判断是否是主模块,并不是说这个属性决定他们是否是主模块,决定是否是主模块的条件只是这个模块有没有被人调用**
具体看示例:
首先创建了模块 lname ,然后判断一下是否是主模块,如果是主模块就输出 main
不是,就输出 not main
,首先直接运行该模块,由于该模块是直接使用,而没有被人调用,所以是主模块,因此输出了 main
,具体看下图:
然后又创建一个 user_lname 模块,里面只是简单的导入了 lname 模块,然后执行,输出的结果是 not main
,因为 lname 模块被该模块调用了,所以不是主模块,输出结果如图:
四、包
包,其实在上面的一些例子中,都创建了不同的包名了,具体可以仔细观察。
在一开始模块的简介中提到,使用模块可以避免函数名和变量名冲突。
相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。但是也要注意,尽量不要与内置函数名字冲突。
但是这里也有个问题,如果不同的人编写的模块名相同怎么办?
为了避免模块名冲突,Python 又引入了按目录来组织模块的方法,称为包(Package)。
比如最开始的例子,就引入了包,这样子做就算有相同的模块名,也不会造成重复,因为包名不同,其实也就是路径不同。如下图,引入了包名后, lname.py 其实变成了 com.Learn.module.nameattributes.lname
仔细观察的人,基本会发现,每一个包目录下面都会有一个 __init__.py
的文件,为什么呢?
因为这个文件是必须的,否则,Python 就把这个目录当成普通目录,而不是一个包 。 __init__.py
可以是空文件,也可以有Python代码,因为 __init__.py
本身就是一个模块,而它对应的模块名就是它的包名。
五、作用域
学习过 Java 的同学都知道,Java 的类里面可以给方法和属性定义公共的( public )或者是私有的 ( private ),这样做主要是为了我们希望有些函数和属性能给别人使用或者只能内部使用。
通过学习 Python 中的模块,其实和 Java 中的类相似,那么我们怎么实现在一个模块中,有的函数和变量给别人使用,有的函数和变量仅仅在模块内部使用呢?
在 Python 中,是通过 _
前缀来实现的。正常的函数和变量名是公开的(public),可以被直接引用,比如:abc,ni12,PI等;类似__xxx__
这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的 __name__
就是特殊变量,还有 __author__
也是特殊变量,用来标明作者。
注意,我们自己的变量一般不要用这种变量名;类似 _xxx
和 __xxx
这样的函数或变量就是非公开的(private),不应该被直接引用,比如 _abc
,__abc
等;
这里是说不应该,而不是不能。因为 Python 种并没有一种方法可以完全限制访问 private 函数或变量,但是,从编程习惯上不应该引用 private 函数或变量。
比如:
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- def _diamond_vip(lv): print('尊敬的钻石会员用户,您好') vip_name = 'DiamondVIP' + str(lv) return vip_name def _gold_vip(lv): print('尊敬的黄金会员用户,您好') vip_name = 'GoldVIP' + str(lv) return vip_name def vip_lv_name(lv): if lv == 1: print(_gold_vip(lv)) elif lv == 2: print(_diamond_vip(lv)) vip_lv_name(2)
输出的结果:
尊敬的钻石会员用户,您好 DiamondVIP2
在这个模块中,我们公开 vip_lv_name
方法函数,而其他内部的逻辑分别在 _diamond_vip
和 _gold_vip
private 函数中实现,因为是内部实现逻辑,调用者根本不需要关心这个函数方法,它只需关心调用 vip_lv_name
的方法函数,所以用 private 是非常有用的代码封装和抽象的方法
一般情况下,外部不需要引用的函数全部定义成 private,只有外部需要引用的函数才定义为 public。