2.4 模块
2.4.1 模块的概念
在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。
为了编写可维护的代码,使用者可以把很多函数分组,分别放到不同的文件里,这样一来每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在Python中,一个.py文件就称之为一个模块(Module)。
Python的强大之处在于有丰富的实现各种功能的标准库和第三方库,另外还允许用户自己建立库文件。常用的标准库有sys、os、glob、socket、threading、thread、queue、time、timeit、subprocess、multiprocessing、signal、select、shutil、functools、itertools、request、collections等。
2.4.2 导入和使用模块中的对象
在Python的默认的安装包中,仅包含部分基础的或者核心的模块,Python在启动时也仅加载了基本模块,在需要的时候才会显式的加载其他模块,这样可以减小程序运行的压力。内置对象可以直接使用,而扩展库需要在正确导入之后才能使用其中的对象和方法。在Python中,导入模块的方法有两种。
(1)import 模块名 [as 别名]
这种方法在导入完成后,需要在以后的使用时在对象之前加上模块名作为前缀,也就是必须以“模块名.对象名”这种方式来进行访问。也可以为导入的模块设置一个别名,然后就可以使用“别名.对象名”的方式来对其中的对象进行调用了。此指令的使用方式如下:
>>> import random
>>> Kee = random.random() #将[0,1)内的随机小数赋值给Kee
>>> import numpy as np
>>> kee = np.array((1,2,3)) #将[1 2 3]赋值给kee
(2)from 模块名 import 对象名[as 别名]
使用这种方式仅导入明确指定的对象,并且可以为导入的对象起别名。这种导入方式可以减少查询次数,提高访问速度,同时减少编程人员需要输入的代码量,而不需要使用模块名作为前缀,它的使用方法如下:
>>> from math import sin as f #调用math模块中的求正弦函数sin并起别名为f
>>> Kee = f(3) #将3的正弦值求出后赋值给Kee
当需要导入模块中的所有对象时,指令如下:
>>> from math import * #一次性调用math模块中的所有函数
>>> Kee = sin(3) #将3的正弦值求出后赋值给Kee
>>> kee = gcd(36,18) #求得36和18的最大公约数后赋值给kee
2.4.3 内置模块__builtins__(此部分稍作了解即可)
内置模块__builtins__包含了Python的全部内置类和内置函数,不需要导入就可以直接使用。
(1)数学相关
绝对值:abs(-1)
最大最小值:max([1,2,3])、min([1,2,3])
序列长度:len('abc')、len([1,2,3])、len((1,2,3))
取模:divmod(5,2) #(2,1)
浮点数:round(80.23456,2) #80.23,返回此浮点数的四舍五入的值
乘方:pow(2,3) #,得结果为8
(2)功能相关
l 函数是否可调用:callable(funcname)
l 类型判断:isinstance(x,list/int)
(3)类型转换
l 转换为整型:int(x)
l 转换为长整型:long(x)
l 转换为浮点型:float(x)
l 转换为复数形式:complex(x)
l 转换为字符型:str(x)
l 转换为列表:list(x)
l 转换为元组:tuple(x)
l 返回表示十六进制数值的字符串:hex(x)
l 返回一个表示八进制数值的字符串:oct(x)
l 返回以数值表达式值为编码的字符:chr(x)
l 以一个字符作为参数,返回对应的ASCⅡ数值或者Unicode数值:ord(x)
2.4.4 time模块
time模块是一个用于处理时间和转换时间格式的模块,其中常用的函数有time()、localtime()、sleep()、strftime()、strptime()。
(1)time()
time()函数用于返回当前时间的时间戳(北京时间1970年01月01日08时00分00秒到现在的浮点秒数)。time()函数的语法如下:
time.time()
(2)localtime()
localtime()函数的作用是格式化时间戳为本地时间。如果secs参数未输入,就以当前时间为转换标准。localtime()函数的语法如下:
time.localtime([secs])
(3)sleep()
sleep()函数用于推迟调用线程的运行,可通过参数secs指定线程挂起的时间。指令如下:
time.sleep(secs)
(4)strftime()
strftime()函数用于接收时间元组,并返回以可读字符串表示的当地时间,格式由参数format决定。strfttime()函数的语法如下:
time.strftime(format[,t])
(5)strptime()
strptime()函数用于根据指定的格式把一个时间字符串解析为时间元组。语法如下:
time.strptime(string[,format])
2.4.5 datetime模块
datetime模块是date与time的结合体,它涵盖了date与time的所有信息,并且它的功能强大,支持0001年到9999年。
datetime定义了两个常量:datetime.MINYEAR和datetime.MAXYEAR。最小年份MINYEAR=1,最大年份MAXYEAR=9999。
datetime模块定义了以下5个类。
datetime.date:表示日期的类。常用的属性有year、month、day。
datetime.time:表示时间的类。常用的属性有hour、minute、second、microsecond。
datetime.datetime:表示日期时间。
datetime.timedelta:表示时间间隔,即两个时间点之间的长度。
datetime.tzinfo:与时区有关的相关信息。
其中,datetime.datetime类的应用最为普遍。下面对该类中的today()、now()两个函数进行一些详细讲解。
(1)today()
today()函数用于返回一个表示当前时间的datetime对象。它的语法如下:
datetime.datetime.today()
该方法的使用示例如下:
>>> import datetime
>>> print(“Today is ”,datetime.datetime.today())
Today is 2018-5-3 10:24:25.9000990
(2)now()
now()方法用于返回一个表示当前日期时间的datetime对象。它的语法如下:
datetime.datetime.now([tz])
它的使用示例如下:
>>> import datetime
>>> print(‘Now is ’,datetime.datetime.now())
Now is 2018-5-3 10:29:55.634641
2.4.6 random模块
random函数存在于Python标准库中,它可以生成随机浮点数、整数、字符串,甚至帮助你随机选择列表序列中的一个元素,打乱一组数据等。在Python3的random模块中,常用的函数主要有random()、randint()、randrange()、choice()、shuffle()、sample()。
(1)random()
random()函数是这个模块中最常用的方法了,它会生成一个随机浮点数,范围是在0.0~1.0之间。它的语法如下:
random.random()
(2)randint()
randint(a, b),用于返回一个指定范围内的随机整数。其中参数a是下限,参数b是上限,生成的随机数n: a <= n <= b。它的语法格式下:
random.randint(a,b)
(3)randrange()
randrange()函数的功能是从指定范围内返回一个随机数。它的语法命令如下:
random.randrange([start],[stop],[step])
(4)choice()
choice()函数的功能为从一个有序序列中随机获取一个元素,其中,这个有序序列不是一种特定的类型,而是泛指一系列的类型,列表,元组,字符串,数值等都被包括在内。它的语法命令如下:
random.choice(一个有序序列)
(5)shuffle()
shuffle()函数的功能为将一个列表中的元素随机打乱,shuffle()函数的语法命令如下:
首先设定一个列表Kee
random.shuffle(p)
(6)sample()
sample()函数的功能为从指定序列中随机获取指定长度的片段,但是在使用这个函数的同时,并不会影响到原有序列的序列。当用此函数对序列进行取片段操作时,如果设定的想要取得的片段长度超出了此有序序列的总长度,系统就会报错,所以使用者在进行取片段操作时要额外注意设定的所取片段的长度。此命令的语法命令如下:
random.sample(有序序列,想要取得的片段的长度)
2.4.7 sys模块
sys模块包括了一组非常实用的服务,内含很多函数方法和变量,用来处理Python运行时配置以及资源,从而可以与前当程序之外的系统环境交互,如:Python解释器。sys模块中的成员有:
(1)argv
argv被人用来获取当前正在执行的命令行参数的参数列表,它很像一个从程序外部获取参数的桥梁。因为从外部获取的参数可以是多个,所以获得的是一个列表,也因此可以用[]的方式来提取其中的元素。当提取元素时,其第一个元素时脚本本身名称,之后才依次是外部给予的参数。它的使用方法如下:
sys.argv[0] #当前程序名
sys.argv[1] #第一个参数
sys.argv[0] #第二个参数
sys.argv #脚本所有参数
(2)exit()
这个函数的功能为中途退出程序。当参数非零时,会引发一个systemexit异常,从而可以在主程序中捕获该异常。用法示例如下:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import sys
print('running...')
try: #捕获异常,运行sys.exit(1),如果在try部分引发了异常则打印出语句。
sys.exit(1)
except SystemExit:
print('SystemExit exit 1')
print('exited')
运行结果如下:
running···
SystemExit exit 1
exited
(3)path
sys.path是Python中的搜索模块的路径集,它是一个列表(list),初始化时使用PYTHONPATH环境变量的值。使用命令如下:
sys.path
(4)executable
executable是有关于Python解释器的绝对路径的,可以利用这个函数来将Python解释器的绝对路径赋值给某个变量,它的使用语法如下:
sys.executable
2.4.8 自定义模块
每个Python源代码文件都可以看做是一个模块。Python编译器通过__name__属性来识别使用者编写的程序的使用方式,每个脚本在运行时都有一个__name__属性,当将脚本作为模块进行导入时,__name__属性的值就会被自动设置为模块名;如果脚本独立运行的话,__name__属性的值就会被编译器自动设定为字符串__main__。
对于一个大型的多功能的程序,为了防止代码行过多而不方便管理,编程人员一般都会使用包来管理程序的多个功能模块。包是Python用来组织命名空间和类的重要方式,可以看做是包含大量Python程序模块的文件夹。在包的每个目录中都必须包含一个__init__.py文件,来告诉系统当前文件夹是一个包。__init__.py文件的主要用途是设置__all__变量以及执行初始化包所袭要的代码,其中__all__变量中定义的对象可以在使用“from···import···”时全部被正确导入。例如,设定了一个包,包的结构如下:
Kee/
__init__.py
kee/
echo.py
echo1.py
echo2.py
此时就可以在所编写的程序中使用下面的代码对echo模块:
import Kee.kee.echo
然后使用完整的名字来访问或者调用其中的成员,例如:
Kee.kee.echo.echofilter(input,output,delay=0.8,atten=5)
如果在__init__.py文件中存在着下面这行代码:
__all__=[‘echo’,’echo1’,’echo2’]
那么就可以使用下面这种方式进行导入:
from Kee.kee import *
然后使用下面这种方式来调用其中的函数模块:
echo.echofilter(input,output,delay=0.8,attention=5)
2.5 运算符与表达式
2.5.1 算术运算符
算数运算符一共有7种,分别是加(+)、减(-)、乘(*)、除(/)、地板除(//)、取余(%)以及求幂值(**)运算,涉及到的知识点比较简单,他们的使用方法如下(表中a,b为假设的两个数值类型操作对象),如表2.4算数运算符所示。
表2.4 算数运算符
符号 |
功能 |
a + b |
对a和b进行相加操作 |
a - b |
对a和b进行相减操作 |
a * b |
对a和b进行乘法操作 |
a / b |
对a和b进行a除b操作 |
a // b |
用a除b并返回计算完成后所得的商 |
a % b |
用a除b并返回计算完成后所得的余数 |
a ** b |
返回a的b次幂 |
2.5.2 关系运算符
本节为大家介绍比较运算类、赋值运算类和位运算类。本节用三张表格来学习下(表中a,b为假设的两个操作对象),如表2.5比较运算类,表2.6赋值运算类,表2.7位运算类所示。
表2.5 比较运算类
符号 |
功能 |
a == b |
比较a,b是否相等,相等返回True,不相等则返回False |
a != b |
比较a,b是否不等,相等返回False,不相等则返回True |
a > b |
比较a是否大于b,大于返回True,不大于则返回False |
a < b |
比较a是否小于b,小于返回True,不小于则返回False |
a >= b |
比较a是否大于等于b,成立返回True,不成立则返回False |
a <= b |
比较a是否小于等于b,成立返回True,不成立则返回False |
表2.6 赋值运算类
符号 |
功能 |
a = b |
简单的赋值运算,将b的值赋给a |
a += b |
加法赋值运算,等效于a = a + b |
a -= b |
减法赋值运算,等效于a = a - b |
a *= b |
乘法赋值运算,等效于a = a * b |
a /= b |
除法赋值运算,等效于a = a / b |
a %= b |
取模赋值运算,等效于a = a % b |
a **= b |
求幂值赋值运算,等效于a = a ** b |
a //= b |
取整(地板除)除赋值运算,等效于a = a // b |
表2.7 位运算类
符号 |
功能 |
a & b |
按位与运算,如果a,b的相应位都为1,则返回结果1,否则为0 |
a | b |
按位或运算,如果a,b的相应位都为0,则返回结果0,否则为1 |
a ^ b |
按位异或运算,当a,b对应位的二进制数不同时,结果为1,相同为0 |
~a |
按位取反运算,对a的每个二进制位上的1变为0,0变为1 |
a << b |
左移运算符,将a的每个二进制位全部左移b个位置,高位丢弃,低位补0 |
a >> b |
右移运算符,将a的每个二进制位全部右移b个位置 |
2.5.3 集合运算符
在Python中,集合是一个无序不重复元素集,基本功能包括关系测试和消除重复元素,关于集合set的运算,包括union(并|),intersection(交&),difference(差-),sysmmetric difference(对称差分^)和判断是否为子集(<),超集(>)等。集合不支持索引、分片或其它类序列的操作。
关于集合的运算操作如下,以集合a([1,2,3])和集合b([3,4,5])为例,如表2.8集合运算类所示。
表2.8 集合运算符
符号 |
功能 |
a | b |
对a和b取并集并返回一个新的集合[1,2,3,4,5] |
a & b |
对a和b取交集并返回一个新的集合[3] |
a - b |
将a中和b相同的元素去掉后形成一个新的集合并返回[1,2] |
a ^ b |
将a和b中不相同的元素取出组成一个新的集合并返回[1,2,4,5] |
a < b |
判断a是否是b的子集,是返回True,不是返回False |
a > b |
判断a是否是b的超集,是返回True,不是返回False |
2.5.4 逻辑运算符
逻辑运算仅支持布尔运算,它的使用方式如表2.9逻辑运算所示。
表2.9 逻辑运算
符号 |
功能 |
a and b |
布尔“与”,若a为False,则返回False,否则返回b的值 |
a or b |
布尔“或”,若a非零,则返回a的值,否则返回b的值 |
not a |
布尔“非”,若a为True,则返回False;若为False,则返回True |
2.5.5 成员运算符
Python支持成员运算,此种运算方式仅会产生True和False两种结果,设变量a=1,列表list=[1,2,3,4],它的使用方式如表2.10成员运算所示。
表2.10 成员运算
符号 |
功能 |
a in list |
若在指定的序列中找到值,则返回True,否则返回False |
a not in list |
若在指定的序列中未找到值,则返回True,否则返回False |
2.5.6 身份运算符
身份运算符用于比较两个对象的存储单元,设定a=1,b=1,它的使用方式如表2.11身份运算所示。
表2.11 身份运算
符号 |
功能 |
a is b |
判断a和b是否引用自同一个对象,是返回1(True),不是则返回0(False) |
a is not b |
判断a和b是否引用自同一个对象,不是返回1(True),是则返回0(False) |
2.5.7 运算符优先级
运算符之间的执行时存在先后顺序的,当一个表达式中出现多个操作符时,这些操作符的被执行顺序就依赖于优先级规则了,Python遵守数学操作符的传统规则。下表列出来了它们之间的优先被执行的等级。如表2.12运算符优先级所示。
表2.12 运算符优先级
符号 |
功能 |
** |
指数(最高优先级) |
~+ - |
按位翻转,一元加号和减号(最后两个的方法名为+@和-@) |
*/%// |
乘、除、取模和地板除 |
+ - |
加法减法 |
>><< |
右移左移运算 |
& |
位‘and’ |
^| |
位运算符 |
<= < > >= |
比较运算符 |
<> == != |
等于运算符 |
= %= /= //= -= += *= **= |
赋值运算符 |
is is not |
身份运算符 |
in not in |
成员运算符 |
not or and |
逻辑运算符 |
2.6 选择结构与循环结构
2.6.1 常用选择结构
选择结构通过判断某些特定条件是否满足来决定下一步的执行流程,是非常重要的控制结构。常见的选择结构有单分支选择结构、双分支选择结构、多分支选择结构和嵌套的分支结构。形式比较灵活多变,具体使用哪一种最终还是取决于要实现的业务逻辑。循环结构和异常处理结构中也可以带有else子句,这也可以看做是一种特殊形式的选择结构。
2.6.2 if...else
当编写某个大型程序时,往往会因为选择了不同的路线,而得到了不同的效果,而这不同路线所组成的结构,也是有一定区别的,在Python程序中,常见的选择结构有单分支、双分支、多分支和选择结构的嵌套等。
单分支,是指如果if条件成立,则继续执行满足条件的代码,不成立则跳过if语句下的代码,继续执行其他代码块。它的语法表达格式如下:
l if 表达式:
语句块
双分支,是指如果if条件成立,则执行满足条件的代码,如果不成立,则跳转到else,执行else下面的代码。它的语法表达格式如下:
l if 表达式:
语句块1
l else:
语句块2
多分支,是指如果if条件成立,则执行满足条件的代码,如果不成立,则跳转到elif进行判断,若elif条件成立,则执行elif条件下的代码,在多分支结构中,可以有多个elif条件语句的存在。如果所有的if条件语句和elif条件语句都不符合,则跳转到else下的代码执行。它的语法表达格式如下:
l if 表达式1:
语句块1
l elif 表达式2:
语句块2
l elif 表达式3:
语句块3
·
·
·
l else:
语句块n
选择结构嵌套,是指在大选择结构下,还在每个分支下包含着小的选择结构,满足条件跳转到大选择结构下的分支后,进入到另一个选择结构中进行更加详细的条件判断和筛选。使用嵌套选择结构时,一定要严格控制好不同级别代码块的缩进量,因为这决定了不同代码块的从属关系和业务逻辑是否能被正确地实现,以及代码能否被Python正确的理解和执行。它的语法表达结构如下:
l if 表达式1:
语句块1
if 表达式2:
语句块2
else:
语句块3
l else:
if 表达式4:
语句块4
以下面的小程序为例:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
name = input('请输入用户名:')
pwd = input('请输入密码:')
if name == "awei" and pwd == "abc123": #第一次判断如果不满足条件,则跳 转到elif语句进行下一步判断
print("欢迎,awei!")
elif name == “awei” or pwd == “abc123”: #第二次判断,如果也不满足条件则跳转到 else语句下的代码进行执行输出
print(”用户名和密码不符”)
else: #如果上两步的条件都不满足,则直接跳转 到此步下的语句执行
print("用户名和密码错误")
2.6.3 while循环
首先介绍第一种循环结构体while循环结构体。以一个小程序为例:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
n = 1
while n<=100: #先判断n是否小于等于100,如果是则执行下面的代码, 不是则终止循环并输出结果
print('当前数字是:',n)
n += 1
从上面的代码可以看出,while循环结构是要先进行条件语句判断再决定是否要继续执行循环操作的。在while循环结构中,判断条件可以是任何合法的表达式,任何非零的或者非空的值均为True。一般在循环次数不确定的情况下使用while循环结构。
2.6.4 for循环
和while相同的是,for循环也是条件前置的循环结构,即它也是需要先进行条件判断再确认是否可以继续执行循环结构中的代码块的。但不同的是for循环结构的书写相对于while循环结构来说更加规范与规整,所以for循环结构一般被用于循环次数比较确定的情况中。尤其适合被应用于枚举和遍历还有迭代对象元素中的场合。示例代码如下:
>>> for i in range(10): #判断i是否在1~10内,是则输出i,不是则终止循环
print("loop:", i )
当选择循环结构时,更推荐大家运用for循环结构来进行循环操作,因为相对于while循环结构来说,for循环结构体思路更加清晰,代码逻辑出错率也比while循环结构低,但并不是说while循环结构就应该被摒弃,两者各有利弊,编译人员在选择时应结合当时的环境和情况。
2.6.5 break与continue语句
break和continue语句是两个中断指令语句,它们经常被应用于while循环和for循环体中,并且常与选择结构结合使用。但这两个指令不同的是,在循环结构中执行break语句后,进程会直接跳出整个循环结构,继续执行循环结构之下的代码块。而在循环结构中执行continue指令后,并不会跳出整个循环结构体,而是终止了当前被执行的循环步骤并将所有这次循环中continue语句之后的代码忽略掉,重新跳转回了循环结构体的顶端,然后再提前进入到下一次执行。
需要注意的是,这两个指令如果过多的话,会让整个程序的结构的条理性显得非常的混乱,降低程序的可读性,所以建议大家在编程时,除非必要,否则不要轻易过多的使用这两个指令。
2.6.6 带else子句的循环结构
虽然while和for为循环结构体,但是这两种循环结构体中仍有条件判断的操作,所以在使用这两个结构体时,可以配合着else子句来使用,使用方式和if··else语句的使用方式类似,其语法结构如下。
while循环:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
n = 1
while n<=100: #先判断n是否小于等于100,如果是则执行下面的代码, 不是则终止循环并输出结果
print('当前数字是:',n)
n += 1
else: #如果不满足n小于等于100,则跳入到此步中执行
print(‘程序结束。’)
for循环:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
for i in range(10): #判断i是否在1~10内,是则输出i,不是则终止循环
print("loop:", i )
else:
print(“程序结束”) #若i不在1~10内,则跳出循环体,执行此步之后的操作
2.7 猜数字游戏
在学习完选择和循环结构后,可以来玩个小游戏放松下,同时也来巩固下本章所学的知识点。
假设有一个数,如果想要确定这个数是几,猜谜者应该怎么设定程序来求得这个数呢?
先来整理下猜数思路,当参与者提出一个数之后,会出现三种情况:
(1)输入的值大于出题者假定的值
(2)输入的值正好等于出题者假定的值
(3)输入的值小于出题者假定的值
如果是情况(2),那么很幸运,猜谜者可以结束进程了,而如果是情况(1)和(3),则需要猜谜者继续输入来猜测,直至猜出这个数为止。
有了程序的大致思路,就可以进行程序代码的设计了。下面就为大家提供一份基础代码以供参考。
在这段代码中,一共有三个变量,一个变量用于记录给定值(number,由系统从1~100中随机择定),一个变量用于记录猜谜者输入的值(number_input,由控制台输入),一个变量用于记录猜谜者输入了多少次(guess,每执行一次循环就进行一次自加操作)。
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import random
number = random.randint(1,100) #这里使用了random随机函数模块来择定需要 进行猜测的数值,范围为1~100。
guess = 0
while True:
number_input = int(input("请输入一个1到100的数字:"))
guess += 1
if number_input == number:
print("恭喜您,您猜对了,您总共猜了 %d 次"%guess)
break
elif number_input < number:
print("您输入的数字小了!")
else:
print("您输入的数字大了!")