一、自定义模块
我们讲过,模块是文件名以“.py”结尾的Python文件。而由于通常每一个Python的代码文件都以“.py”结尾,因此每个代码文件都可以是一个模块。
例如,我们在module.py文件中写入如下代码并保存:
#!/usr/bin/python# coding: utf-8# 定义一个类型别名Number = int | floatdef my_power(num: Number, exp: Number) -> Number:return num ** expdef my_sqrt(num: Number) -> Number:return num ** 0.5
先解释一下代码:
第一行注释内容用于告知系统Python解释器所在路径,这通常用在Linux系统上,如果使用conda进行Python环境管理,则此处需写入conda创建的虚拟环境的Python解释器路径,多数时候不写也没有关系;
第二行是告知解释器文件的文字编码形式是UTF-8(代码中一般不区分大小写),这是由于Python 2.X是以ASCII形式解析文件,遇到写入中文等非英文时就会出现错误,Python 3.X默认以UTF-8编码,但是依然可以写入这一行,除此之外还可以写latin-1、gbk等其他编码形式;
定义Number为int或float数据类型的别称,用于在函数书写时简化内容,从这也能看出Python的灵活性。
模块module.py定义了计算幂和平方根的函数,下面我们在test.py文件中来调用这些函数,调用方法我们上个章节已经讲过,此处不赘述:
# coding: utf-8import moduleprint(module.my_power(2, 3))# Output: 8print(module.my_sqrt(4))# Output: 2.0
在调用自定义的模块时,import语句后的模块名通常是模块文件名去除“.py”后的内容。由于Python不支持命名字符中出现空格以及下划线以外的字符,所以模块文件命名尽量是字母、下划线、数字(不出现在首位)的组合。尽管类似“module-1.py”的模块可以以“import module_1”的方式(短横线变下划线)导入,但是笔者并不推荐。
二、代码包
包(Package)是一个层次目录(文件夹)结构,其定义了一个由模块及子包(注意子包也是包,也有包的性质)下的内容组成的Python应用环境。简单来说,包就是文件夹,但该文件夹下必须存在__init__.py文件, 用于标识当前文件夹是一个包,该文件内容可以为空。通常,解释器或者一些IDE会在运行程序时自动添加__init__.py,无需手动操作。
例如,设置名为MyProject的Python项目,创建名为MyProject的目录,其中包含数个模块及子目录(存放数据、素材、子包等)构成,那么这个MyProject就是一个Python包:
MyProject|-- __init__.py|-- main.py|-- module.py|-+ sub_package|-|-- __init__.py|-|-- sub_module.py|-+ others(images, data, etc.)
目录下,笔者通常喜欢加一个main.py文件,并在里面添加主程序入口,便于解释器统筹其他模块及子包:
# coding: utf-8import module as mfrom sub_package.sub_module import *# 主程序入口if __name__ == '__main__':print("Program start")
从from语句可以看出,要调用子包里的模块,可以使用“包.模块”的方式,这其实是一种包内相对路径,“.”替代了文件路径中的“/”(斜杠)目录分隔符。Windows中的目录(文件夹)分隔符是“\”(反斜杠),但这在多数编程语言中通常表示转义字符,即改变某个字符的原有含义,例如“\n”将字母“n”转义为换行、“\t”将字母“t”转义为Tab、“\””转义英文引号用于避免多层引号嵌套产生的歧义等。因此,如果代码中需要表示“\”(例如表示Windows环境下的文件路径时),正确的写法是“\\”,利用前一个反斜杠转义后一个反斜杠,使得后者发挥其原本作用。
往期回顾: