《看漫画学Python》学习笔记

封面

目录

 

前言

  • “Python”中文翻译“蟒蛇”

  • Python的优点:

    • 简单、易学、免费、开源:Python简单、易学。我们可以自由发布其复制版本,阅读、修改其源代码,将其(部分)用于新软件中。
    • 解释型:Python是边解释边执行的,Python解释器会将源代码转换为中间字节码形式,然后将其解释为机器语言并执行。
    • 可移植:Python解释器已被移植在许多平台上,Python程序无须经过修改就可以在多个平台上运行。
    • 代码规范:Python所采用的强制缩进的方式,使得其代码具有极佳的可读性。
    • 面向对象:与C++和Java等相比,Python以强大而简单的方式实现了面向对象编程。
    • 胶水语言:标准版本的Python调用C语言,并可以借助C语言的接口驱动调用所有编程语言。
    • 丰富的库:Python的标准库种类繁多,可以帮助处理各种工作,我们不需要安装就可以直接使用这些库。
    • 动态类型:Python不会检查数据类型,在声明变量时不需要指定数据类型。

编写和运行Python程序方式:

  • 交互方式
  • 文件方式

1.交互方式

Python安装包提供了交互式运行工具——Python Shell,在安装好Python后,我们就可以单击Windows“开始”菜单打开Python 3.x了。

2.文件方式

通过文件方式编写和运行Python程序时,首先需要编写Python代码,然后在Windows下启动命令提示符,再使用Python指令运行Python代码文件。
编写Python代码时,既可以使用任意一种文本编辑工具,也可以使用专业的IDE(Integrated Development Environments,集成开发环境)工具。

一些基础概念

标识符

标识符就是变量、函数、属性、类、模块等可以由程序员指定名称的代码元素。构成标识符的字符均遵循一定的命名规则。

注:Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。

  • Python中标识符的命名规则:
    • 区分大小写:Myname与myname是两个不同的标识符。
    • 首字符可以是下画线(_)或字母,但不能是数字。
    • 除首字符外的其他字符必须是下画线、字母和数字。
    • 关键字不能作为标识符。
    • 不要使用Python的内置函数作为自己的标识符。

关键字

关键字是由语言本身定义好的有特殊含义的代码元素

变量

在Python中为一个变量赋值的同时就声明了该变量,该变量的数据类型就是赋值数据所属的类型,该变量还可以接收其他类型的数据。
·注:Python中,声明变量后,也可以接受其他类型的数据。这是与Java和C等编程语言的区别。

语句

Python代码是由关键字、标识符、表达式和语句等构成的,语句是代码的重要组成部分。在Python中,一行代码表示一条语句,在一般情况下语句结束时不加分号。

代码注释

在使用#(井号)时,#位于注释行的开头,#后面有一个空格,接着是注释的内容。

模块

在Python中一个模块就是一个文件,模块是保存代码的最小单位,在模块中可以声明变量、函数、属性和类等Python代码元素。

  • 一个模块访问另一个模块中的代码元素——三种导入语句:
    • import<模块名>:通过这种方式会导入m2模块的所有代码元素,在访问时需要加前缀“m2.”
    • from<模块名>import<代码元素>:通过这种方式会导入m2中的x变量,在访问时不需要加前缀“m2.”
    • from<模块名>import<代码元素>as<代码元素别名>:与②类似,在当前m1模块的代码元素(x变量)与要导入的m2模块的代码元素(x变量)名称有冲突时,可以给要导入的代码元素(m2中的x)一个别名x2

数字类型的数据

在Python中有6种主要的内置数据类型:数字、字符串、列表、元组、集合和字典。列表、元组、集合和字典可以容纳多项数据,在本书中把它们统称为容器类型的数据。

Python中的数字类型有4种:整数类型、浮点类型、复数类型和布尔类型。需要注意的是,布尔类型也是数字类型,它事实上是整数类型的一种。

Python中的整数类型为int类

示例:

Python的浮点类型为float类,浮点类型主要用来存储小数数值

示例:

Python的复数类型

示例:

Python的布尔类型为bool类

bool是int的子类,他只有两个值:True和Flase

示例:

数字类型的相互转换

在Python的数字类型中,除复数隐式类型的转换数字之间可以进行数学计算,在进行数学计算时若数字类型不同,则会发生隐式类型的转换。

隐式类型的转换

数字之间可以进行数学计算,在进行数学计算时若数字类型不同,则会发生隐式类型的转换
示例:

显式类型的转换

示例:

运算符

我们可以通过运算符把数据连接起来,形成表达式,进而通过表达式进行运算,最后返回一个结果。

算数运算符

算术运算符用于组织整数类型和浮点类型的数据,有一元运算符和二元运算符之分。
一元算术运算符有两个:+(正号)和-(负号),例如:+a还是a,-a是对a的取反运算。
二元算术运算符如表所示。

·注:True被当作整数1进行运算,False被当作整数0进行运算。在操作数中如有浮点数字,则表达式的计算结果也是浮点类型。

比较运算符

比较运算符用于比较两个表达式的大小,其结果是布尔类型的数据,即True或False。

·注:比较运算符可用于任意类型的数据,但参与比较的两种类型的数据要相互兼容,即能进行隐式转换。例如:整数、浮点数和布尔这三种类型是相互兼容的。

逻辑运算符

逻辑运算符用于对布尔型变量进行运算,其结果也是布尔型。

·注:Python也采用了“短路”设计。

位运算符

位运算是以二进位(bit)为单位进行运算的,操作数和结果都是整数类型的数据。

或运算:

与运算:

异或运算:

取反运算(原码、补码、反码):

赋值运算符

补充:进制的前缀与后缀

运算符的优先级

程序流程控制

控制程序的流程,使得程序具有“判断能力”,能够像人脑一样分析问题。

分支语句(条件语句)

if语句三种结构:

if结构
if-else结构
if-elif-else结构

if结构

语法:

·注:1个Tab=4个半角空格

示例:

if-else结构

语法:


示例:

if-elif-else结构

语法:


示例:

循环语句

Python支持两种循环语句:while和for。

while语句

语法:

示例:

while-else语句


示例:

for语句

语法:

示例:

for-else语句


示例:

跳转语句

跳转语句能够改变程序的执行顺序,包括break、continue和return。break和continue用于循环体中,而return用于函数中。

break语句

break语句用于强行退出循环体,不再执行循环体中剩余的语句。

示例:

continue语句

continue语句用于结束本次循环,跳过循环体中尚未执行的语句,接着进行终止条件的判断,以决定是否继续循环。

示例:

循环语句实践:计算水仙花数

水仙花数是一个三位数,三位数各位的立方之和等于三位数本身。

关于else的注意事项

在循环体正常结束时会执行else语句,如果发生中断,则不运行else语句

容器类型的数据

Python内置的数据类型如序列(列表、元组等)、集合和字典等可以容纳多项数据,我们称它们为容器类型的数据。

序列

序列(sequence)是一种可迭代的、元素有序的容器类型的数据。
序列包括列表(list)、字符串(str)、元组(tuple)和字节序列(bytes)等。

序列的索引操作

序列中的元素都是有序的,每一个元素都带有序号,这个序号叫作索引。索引有正值索引和负值索引之分。

我们是通过下标运算符访问序列中的元素的,下标运算符是跟在容器数据后的一对中括号([]),中括号带有参数,对于序列类型的数据,这个参数就是元素的索引序号。

示例:

加和乘操作

加(+)和乘()运算符也可以用于序列中的元素操作。加(+)运算符可以将两个序列连接起来,乘()运算符可以将两个序列重复多次。

示例:

切片操作

序列的切片(Slicing)就是从序列中切分出小的子序列。
切片运算符的语法形式为[start:end:step]。其中,start是开始索引,end是结束索引,step是步长(切片时获取的元素的间隔,可以为正整数,也可以为负整数)。
注意:切下的小切片包括start位置的元素,但不包括end位置的元素,start和end都可以省略。

示例:

成员测试

成员测试运算符有两个:in和not in,in用于测试是否包含某一个元素,not in用于测试是否不包含某一个元素。

示例:

列表

列表(list)是一种可变序列类型,我们可以追加、插入、删除和替换列表中的元素。

创建列表

创建列表有两种方法。

1 list(iterable)函数:参数iterable是可迭代对象(字符串、列表、元组、集合和字典等)。
2 [元素1,元素2,元素3,⋯]:指定具体的列表元素,元素之间以逗号分隔,列表元素需要使用中括号括起来。

示例:

追加元素

列表是可变的序列对象,列表可以追加元素。

1 在列表中追加单个元素时,可以使用列表的append(x)方法。
2 在列表中追加多个元素时,可以使用加(+)运算符或列表的extend(t)方法。

·区分:

示例:

插入元素

想向列表中插入元素时,可以使用列表的list.insert(i,x)方法,其中,i指定索引位置,x是要插入的元素。

示例:

替换元素

想替换列表中的元素时,将列表下标索引元素放在赋值符号(=)的左边,进行赋值即可。

示例:

删除元素

想在列表中删除元素时,可使用列表的list.remove(x)方法,如果找到匹配的元素x,则删除该元素,如果找到多个匹配的元素,则只删除第一个匹配的元素。

示例:

元组

元组(tuple)是一种不可变序列类型。

创建元组

创建元组时有两种方法。

1 tuple(iterable)函数:参数iterable是可迭代对象(字符串、列表、元组、集合和字典等)。
2 (元素1,元素2,元素3,⋯):指定具体的元组元素,元素之间以逗号分隔。对于元组元素,可以使用小括号括起来,也可以省略小括号。

示例:

元组拆包

创建元组,并将多个数据放到元组中,这个过程被称为元组打包。
与元组打包相反的操作是拆包,就是将元组中的元素取出,分别赋值给不同的变量。

示例:

集合

集合(set)是一种可迭代的、无序的、不能包含重复元素的容器类型的数据。

创建集合

我们可以通过以下两种方式创建集合。

1 set(iterable)函数:参数iterable是可迭代对象(字符串、列表、元组、集合和字典等)。
2 {元素1,元素2,元素3,⋯}:指定具体的集合元素,元素之间以逗号分隔。对于集合元素,需要使用大括号括起来。

示例:

修改集合

修改集合类似于修改列表,可以向其中插入和删除元素。修改可变集合有如右所示的常用方法。

add(elem):添加元素,如果元素已经存在,则不能添加,不会抛出错误。
remove(elem):删除元素,如果元素不存在,则抛出错误。
clear( ):清除集合

示例:

字典

字典(dict)是可迭代的、通过键(key)来访问元素的可变的容器类型的数据。
字典由两部分视图构成:键视图和值视图。键视图不能包含重复的元素,值视图能。在键视图中,键和值是成对出现的。

创建字典

我们可以通过以下两种方法创建字典。

1 dict( )函数。
2 {key1:value1,key2:value2,...,key_n:value_n}:指定具体的字典键值对,键值对之间以逗号分隔,最后用大括号括起来。

示例:

修改字典

字典可以被修改,但都是针对键和值同时操作的,对字典的修改包括添加、替换和删除。

示例:

访问字典视图

我们可以通过字典中的三种方法访问字典视图。

items( ):返回字典的所有键值对视图。
keys( ):返回字典键视图。
values( ):返回字典值视图。

解释:
第2行:返回字典的所有键值对视图dict_items
第4行:dict_items可以使用list( )函数返回键值对列表
第6行:返回字典键视图dict_keys
第8行:dict_keys可以使用list( )函数返回键列表
第10行:返回字典值视图dict_values
第12行:dict_values可以使用list( )函数返回值列表

遍历字典

什么是遍历

示例:

字符串

字符串的表示方式

字符串有三种表示方式:普通字符串、原始字符串和长字符串。

普通字符串

普通字符串指用单引号(')或双引号(")括起来的字符串。

字符转义

常用转义符:

示例:

原始字符串

示例:

长字符串

如果要使用字符串表示一篇文章,其中包含了换行、缩进等排版字符,则可以使用长字符串表示。对于长字符串,要使用三个单引号(''')或三个双引号(""")括起来。

示例:

字符串与数字的相互转换

字符串和数字是不兼容的两种数据类型,不能进行隐式转换,只能通过函数进行显式转换。

将字符串转换为数字

将字符串转换为数字,可以使用int( )和float( )实现,如果成功则返回数字,否则引发异常。

示例:

在默认情况下,int( )函数都将字符串参数当作十进制数字进行转换,所以int('AB')会失败。int( )函数也可以指定基数(进制)。

将数字转换为字符串【str()】

将数字转换为字符串,可以使用str( )函数,str( )函数可以将很多类型的数据都转换为字符串。

示例:

格式化字符串【format()】

使用占位符

要想将表达式的计算结果插入字符串中,则需要用到占位符。对于占位符,使用一对大括号({})表示。

默认占位符

参数序号占位符

参数名占位符

示例:

格式化控制符

在占位符中还可以有格式化控制符,对字符串的格式进行更加精准的控制

格式化控制符位于占位符索引或占位符名字的后面,之间用冒号分隔,语法:{参数序号:格式控制符}或{参数名:格式控制符}。

字符串的格式化控制符及其说明如下表所示:

示例:

操作字符串

字符串查找

字符串的find( )方法用于查找子字符串。该方法的语法为str.find(sub[,start[,end]]),表示:在索引start到end之间查找子字符串sub,如果找到,则返回最左端位置的索引;如果没有找到,则返回-1。

注:在Python文档中[]表示可以省略部分内容,find()方法的参数[,start[,end]]表示start和end都可以省略

示例:

字符串替换

若想进行字符串替换,则可以使用replace( )方法替换匹配的子字符串,返回值是替换之后的字符串。该方法的语法为str.replace(old,new[,count]),表示:用new子字符串替换old子字符串。count参数指定了替换old子字符串的个数,如果count被省略,则替换所有old子字符串。

示例:

字符串分割

若想进行字符串分割,则可以使用split( )方法,按照子字符串来分割字符串,返回字符串列表对象。该方法的语法为str.split(sep=None,maxsplit=-1),表示:使用sep子字符串分割字符串str。maxsplit是最大分割次数,如果maxsplit被省略,则表示不限制分割次数。

示例:

实践:统计英文文章中单词出现的频率



函数

定义函数

自定义函数的语法格式如下:

形式参数

由于定义函数时的参数不是实际数据,会在调用函数时传递给他们是实际数据,所以我们定义函数时的参数成为形式参数,简称形参;称调用函数时传递的实际数据为实际参数,简称实参。可以将形参理解为在函数中定义的变量。

示例:

调用函数

使用位置参数调用函数

在调用函数时传递的实参与定义函数时的形参顺序一致,这是调用函数的基本形式。

示例:

使用关键字参数调用函数

在调用函数时可以采用“关键字=实参”的形式,其中,关键字的名称就是定义函数时形参的名称。

示例:

参数的默认值

示例:

可变参数

基于元组的可变参数(*可变参数)

*可变参数在函数中被组装成一个元组。

示例:

基于字典的可变参数(**可变参数)

**可变参数在函数中被组装成一个字典。

示例:

函数中变量的作用域

变量可以在模块中创建,作用域(变量的有效范围)是整个模块,被称为全局变量。变量也可以在函数中创建,在默认情况下作用域是整个函数,被称为局部变量。

示例:



函数类型

Python中的任意一个函数都有数据类型,这种数据类型是function,被称为函数类型。

理解函数类型

函数类型的数据与其他类型的数据是一样的,任意类型的数据都可以作为函数返回值使用,还可以作为函数参数使用。因此,一个函数可以作为另一个函数返回值使用,也可以作为另一个函数参数使用。

示例:


add( )和sub( )函数有两个数字参数,具有相同的函数类型。square( )函数只有一个数字参数,所以square( )与add( )、sub( )函数的类型不同。

数据处理的函数

在Python中定义了一些用于数据处理的函数,如filter( )和map( )等。我们先介绍filter( )函数。

过滤函数filter( )

filter( )函数用于对容器中的元素进行过滤处理。
filter( )函数的语法如下:

参数function是一个提供过滤条件的函数,返回布尔值。
参数iterable是容器类型的数据。

示例:

映射函数map( )

map( )函数用于对容器中的元素进行映射(或变换)。例如:我想将列表中的所有元素都乘以2,返回新的列表。
map( )函数的语法如下:

参数function是一个提供变换规则的函数,返回变换之后的元素。
参数iterable是容器类型的数据。

示例:

lambda( )函数

我们之前学习的函数都是有名称的函数,例如在8.1节定义的rect_area( )函数,rect_area就是其函数名。我们也可以定义匿名函数,匿名函数就是没有名称的函数。
在Python中使用lambda关键字定义匿名函数。lambda关键字定义的函数也被称为lambda( )函数,定义lambda( )函数的语法如下。

“参数列表”与函数的参数列表是一样的,但不需要用小括号括起来

lambda( )函数与有名称的函数一样,都是函数类型。add( )和sub( )函数可以被lambda( )函数替代。

示例:

类与对象

类和对象都是面向对象中的重要概念。面向对象是一种编程思想,即按照真实世界的思维方式构建软件系统。

定义类

Python中的数据类型都是类,我们可以自定义类,即创建一种新的数据类型。Python中类的定义语法格式如图所示。

示例:

小汽车(Car)类继承了object类,object类是所有类的根类,在Python中任何一个类(除object外)都直接或间接地继承了object,直接继承object时(object)部分的代码可以省略。
pass语句的作用:pass语句只用于维持程序结构的完整。我们在编程时若不想马上编写某些代码,又不想有语法错误,就可以使用pass语句占位。

创建对象

类相当于一个模板,依据这样的模板来创建对象,就是类的实例化,所以对象也被称为“实例”。

示例:

类的成员

分类:

成员变量也被称为数据成员,保存了类或对象的数据。例如,学生的姓名和学号。
构造方法是一种特殊的函数,用于初始化类的成员变量。
成员方法是在类中定义的函数。
属性是对类进行封装而提供的特殊方法。

实例变量

实例变量就是对象个体特有的“数据”,例如狗狗的名称和年龄等。

示例:

构造方法

类中的__init__( )方法是一个非常特殊的方法,用来创建和初始化实例变量,这种方法就是“构造方法”。在定义__init__( )方法时,它的第1个参数应该是self,之后的参数用来初始化实例变量。调用构造方法时不需要传入self参数。

示例:

实例方法

实例方法与实例变量一样,都是某个实例(或对象)个体特有的方法。
定义实例方法时,它的第1个参数也应该是self,这会将当前实例与该方法绑定起来,这也说明该方法属于实例。在调用方法时不需要传入self,类似于构造方法。

示例:

类变量

类变量是属于类的变量,不属于单个对象。
例如,有一个Account(银行账户)类,它有三个成员变量:amount(账户金额)、interest_rate (利率)和owner(账户名)。amount和owner对于每一个账户都是不同的,而interest_rate对于所有账户都是相同的。amount和owners是实例变量,interest_rate是所有账户实例共享的变量,它属于类,被称为“类变量”。、

类方法

类方法与类变量类似,属于类,不属于个体实例。在定义类方法时,它的第1个参数不是self,而是类本身。

示例:

注:

封装性

封装性是面向对象重要的基本特性之一。封装隐藏了对象的内部细节,只保留有限的对外接口,外部调用者不用关心对象的内部细节,使得操作对象变得简单。

例如,一台计算机内部极其复杂,有主板、CPU、硬盘和内存等,而一般人不需要了解它的内部细节。计算机制造商用机箱把计算机封装起来,对外提供了一些接口,如鼠标、键盘和显示器等,使用计算机就变得非常简单。

私有变量

为了防止外部调用者随意存取类的内部数据(成员变量),内部数据(成员变量)会被封装为“私有变量”。外部调用者只能通过方法调用私有变量。

在默认情况下,Python中的变量是公有的,可以在类的外部访问它们。如果想让它们成为私有变量,则在变量前加上双下画线(__)即可。

示例:

由于在类的外部不可以访问私有变量,因此上述代码在运行时会发生错误。

私有方法

私有方法与私有变量的封装是类似的,在方法前加上双下画线(__)就是私有方法了。

示例:

由于在类的外部不可以访问私有方法,因此上述代码在运行时会发生错误.

使用属性

为了实现对象的封装,在一个类中不应该有公有的成员变量,这些成员变量应该被设计为私有的,然后通过公有的set (赋值)和get(取值)方法访问。

示例:


属性在本质上就是两个方法,在方法前加上装饰器使得方法成为属性。属性使用起来类似于公有变量,可以在赋值符(=)左边或右边,左边被赋值,右边取值。

继承性

继承性也是面向对象重要的基本特性之一。

9.6.1 Python中的继承

在Python中声明子类继承父类,语法很简单,定义类时在类的后面使用一对小括号指定它的父类就可以了。

示例:


多继承

在Python中,当子类继承多个父类时,如果在多个父类中有相同的成员方法或成员变量,则子类优先继承左边父类中的成员方法或成员变量,从左到右继承级别从高到低。

示例:

方法重写

如果子类的方法名与父类的方法名相同,则在这种情况下,子类的方法会重写(Override)父类的同名方法。

示例:

多态性

多态性也是面向对象重要的基本特性之一。“多态”指对象可以表现出多种形态。

继承与多态

在多个子类继承父类,并重写父类方法后,这些子类所创建的对象之间就是多态的。这些对象采用不同的方式实现父类方法。

示例:

鸭子类型测试与多态

Python的多态性更加灵活,支持鸭子类型测试。鸭子类型测试指:若看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟可以被称为鸭子。

由于支持鸭子类型测试,所以Python解释器不检查发生多态的对象是否继承了同一个父类,只要它们有相同的行为(方法),它们之间就是多态的。

例如,我们设计一个函数start( ),它接收具有“叫”speak( )方法的对象,代码如下:

我们定义了几个类,它们都有speak( )方法。

start( )函数可以接收所有speak( )方法对象。

异常处理

为增强程序的健壮性,我们也需要考虑异常处理方面的内容。例如,在读取文件时需要考虑文件不存在、文件格式不正确等异常情况。

第一个异常——除零异常

在数学中,任何整数都不能除以0,如果在计算机程序中将整数除以0,则会引发异常。

示例:


捕获异常

我们不能防止用户输入0,但在出现异常后我们能捕获并处理异常,不至于让程序发生终止并退出。亡羊补牢,为时未晚。

try-except语句

在try代码块中包含在执行过程中可能引发异常的语句,如果没有发生异常,则跳到except代码块执行,这就是异常捕获。

异常捕获是通过try-except语句实现的,基本的try-except语句的语法如下。

try-except语句的执行流程如下。

示例:

从运行的结果可以看出,在输入数字0后,异常发生,跳到except代码块执行。

修改示例:

多个except代码块

多条语句可能会引发多种不同的异常,对每一种异常都会采用不同的处理方式。针对这种情况,我们可以在一个try后面跟多个except代码块,语法如下:

示例:

多重异常捕获

示例:

try-except语句嵌套

示例:

使用finally代码块释放资源

有时在try-except语句中会占用一些资源,例如打开的文件、网络连接、打开的数据库及数据结果集等都会占用计算机资源,需要程序员释放这些资源。为了确保这些资源能够被释放,可以使用finally代码块。

在try-except语句后面还可以跟一个finally代码块,语法如下。

无论是try代码块正常结束还是except代码块异常结束,都会执行finally代码块。

示例:

自定义异常类

示例:

手动引发异常

示例:

常用的内置模块

数学计算模块——math

在math模块中包含数学运算相关的函数等,例如指数、对数、平方根和三角函数等。

本节介绍math模块中的一些常用函数。

示例:

日期时间模块——datetime

Python官方提供的日期和时间模块主要是datetime模块。在datetime模块中提供了如下几个类。

datetime:包含时间和日期。
date:只包含日期。
time:只包含时间。
timedelta:计算时间跨度。
tzinfo:时区信息。

datetime类

datetime类表示日期和时间等信息,我们可以使用如下构造方法创建datetime对象:

示例:

datetime类的常用方法如下。

datetime.today( ):返回当前的本地日期和时间。

datetime.now(tz=None):返回指定时区的当前日期和时间,参数tz用于设置时区,如果参数tz为None或省略,则等同于today( )。

datetime.fromtimestamp(timestamp,tz=None):返回与UNIX时间戳对应的本地日期和时间。UNIX时间戳是从1970年1月1日00:00:00开始到现在为止的总秒数。我们在Python Shell中运行代码,看看运行结果怎样。

示例:

date类

date类表示日期信息,我们可以使用如下构造方法创建date对象:

这些参数的含义和取值范围与datetime类一样

date类的常用方法如下。

date.today( ):返回当前的本地日期。

date.fromtimestamp(timestamp):返回与UNIX时间戳对应的本地日期。

示例:

time类

time类表示一天中的时间信息,我们可以使用如下构造方法创建time对象:

这些参数的含义和取值范围与datetime类一样。

示例:

计算时间跨度类——timedelta

timedelta类的构造方法:

其中的所有参数都可以为整数或浮点数,也可以为正数或负数,如右表所示。

示例:

timedelta可以表示正数或负数时间的间隔,如下代码是等效的。

将日期时间与字符串相互转换

我们经常会遇到将日期时间与字符串相互转换的情况。

1 将日期时间对象转换为字符串时,称之为日期时间格式化。在Python中使用strftime( )方法进行日期时间的格式化,在datetime、date和time三个类中都有一个实例方法strftime(format)。

2 将字符串转换为日期时间对象的过程,叫作日期时间解析。在Python中使用datetime.strptime(date_string,format)类方法进行日期时间解析。

在strftime( )和strptime( )方法中都有一个格式化参数format,用来控制日期时间的格式,常用的日期和时间格式控制符如下表所示。

示例:

正则表达式模块——re

正则表达式指预先定义好一个“字符串模板”,通过这个“字符串模板”可以匹配、查找和替换那些匹配“字符串模板”的字符串。

字符串匹配

字符串匹配指验证一个字符串是否符合指定的“字符串模板”,常用于用户输入验证。例如,用户在注册时要输入邮箱,所以需要验证邮箱是否有效,这就要用到字符串匹配验证。
我们使用match(p,text)函数进行字符串匹配,其中的参数p是正则表达式,即字符串模板,text是要验证的字符串。如果匹配成功,则返回一个Match对象(匹配对象),否则返回None。

示例:

字符串查找

字符串查找指从一个字符串中查找匹配正则表达式的子字符串,常用于数据分析、网络爬虫等数据处理中。

常用的字符串查找函数如下。

search(p,text):在text字符串中查找匹配的内容,如果找到,则返回第1个匹配的Match对象,否则返回None。p是正则表达式。

findall(p,text):在text字符串中查找所有匹配的内容,如果找到,则返回所有匹配的字符串列表;如果一个都没有匹配,则返回None。p是正则表达式。

示例:

字符串替换

正则表达式的字符串替换函数是sub( ),该函数替换匹配的子字符串,返回值是替换之后的字符串,其语法格式如下:

其中,参数pattern是正则表达式;参数repl是用于替换的新字符串;参数string是即将被替换的旧字符串;参数count是要替换的最大数量,默认值为零,表示不限制替换数量。

字符串分割

在Python中使用re模块中的split( )函数进行字符串分割,该函数按照匹配的子字符串进行字符串分割,返回字符串列表对象,其语法格式如下:

其中,参数pattern是正则表达式;参数string是要分割的字符串;参数maxsplit是最大分割次数;maxsplit的默认值为零,表示分割次数没有限制。

文件读写

文件是数据的载体,程序可以从文件中读取数据,也可以将数据写入文件中。

打开文件

我们在使用文件之前要先将文件打开,这通过open( )函数实现。open( )函数的语法如下:

open( )函数中的参数还有很多,这里介绍4个常用参数,这些参数的含义如下。

1. file参数
file参数用于表示要打开的文件,可以是字符串或整数。如果file是字符串,则表示文件名,文件名既可以是当前目录的相对路径,也可以是绝对路径;如果file是整数,则表示一个已经打开的文件。

2. mode参数
mode参数用于设置文件打开模式,用字符串表示,例如rb表示以只读模式打开二进制文件。用于设置文件打开模式的字符串中的每一个字符都表示不同的含义,对这些字符的具体说明如下。

t:以文本文件模式打开文件。
b:以二进制文件模式打开文件。
r:以只读模式打开文件。
w:以只写模式打开文件,不能读内容。如果文件不存在,则创建文件;如果文件存在,则覆盖文件的内容。
x:以独占创建模式打开文件,如果文件不存在,则创建并以写入模式打开;如果文件已存在,则引发FileExistsError异常。
a:以追加模式打开文件,不能读内容。如果文件不存在,则创建文件;如果文件存在,则在文件末尾追加。
+:以更新(读写)模式打开文件,必须与r、w或a组合使用,才能设置文件为读写模式。

这些字符可以进行组合,以表示不同类型的文件的打开模式,如下表所示。

3. encoding参数
encoding用来指定打开文件时的文件编码,默认是UTF-8编码,主要用于打开文本文件。

4. errors参数
errors参数用来指定在文本文件发生编码错误时如何处理。推荐errors参数的取值为'ignore',表示在遇到编码错误时忽略该错误,程序会继续执行,不会退出。

示例:

注:

关闭文件

在打开文件后,如果不再使用该文件,则应该将其关闭,会用到close( )方法。

在finally代码块中关闭文件

对文件的操作往往会抛出异常,为了保证对文件的操作无论是正常结束还异常结束,都能够关闭文件,我们应该将对close( )方法的调用放在异常处理的finally代码块中。

示例:

在with as代码块中关闭文件

with as提供了一个代码块,在as后面声明一个资源变量,在with as代码块结束之后自动释放资源。

示例:

读写文本文件

读写文本文件的相关方法如下。

read(size=-1):从文件中读取字符串,size限制读取的字符数,size=-1指对读取的字符数没有限制。

readline(size=-1):在读取到换行符或文件尾时返回单行字符串。如果已经到文件尾,则返回一个空字符串。size是限制读取的字符数,size=-1表示没有限制。

readlines( ):读取文件数据到一个字符串列表中,每一行数据都是列表的一个元素。

write(s):将字符串s写入文件中,并返回写入的字符数。

writelines(lines):向文件中写入一个字符串列表。不添加行分隔符,因此通常为每一行末尾都提供行分隔符。

flush( ):刷新写缓冲区,在文件没有关闭的情况下将数据写入文件中。

复制文本文件

读写二进制文件

二进制文件的读写单位是字节,不需要考虑编码问题。二进制文件的主要读写方法如下。

read(size=-1):从文件中读取字节,size限制读取的字节数,如果size=-1,则读取全部字节。

readline(size=-1):从文件中读取并返回一行。size是限制读取的行数,如果size=-1,则没有限制。

readlines( ):读取文件数据到一个字节列表中,每一行数据都是列表的一个元素。、

write(b):写入b字节,并返回写入的字节数。

writelines(lines):向文件中写入一个字节列表。不添加行分隔符,因此通常为每一行末尾都提供行分隔符。

flush( ):刷新写缓冲区,在文件没有关闭的情况下将数据写入文件中。

复制二进制文件

注:

图形用户界面

Python中的图形用户界面开发库

注:Qt是一个跨平台的C++应用程序开发框架,被广泛用于开发GUI程序,也可用于开发非GUI程序。

1 TkinterTkinter是Python官方提供的图形用户界面开发库,用于封装Tk GUI工具包,跨平台。但是,Tkinter工具包所包含的控件较少,帮助文档不健全,不便于我们开发复杂的图形用户界面。

2 PyQtPyQt是非Python官方提供的图形用户界面开发库,用于封装Qt工具包,跨平台。若想使用PyQt工具包,则需要额外安装软件包。

3 wxPythonwxPython是非Python官方提供的图形用户界面开发库,也跨平台。它提供了丰富的控件,可用于开发复杂的图形用户界面。它的工具包帮助文档很完善,案例也很丰富。

安装wxPython

在命令提示符(终端)窗口输入pip指令:
在Windows平台上通过pip指令安装wxPython,在命令提示符窗口输入如下指令。

如果安装成功,则可以出现如下窗口。

第一个wxPython程序

图形用户界面主要是由窗口及窗口中的控件构成的,编写wxPython程序其实主要是创建窗口和添加控件的过程。

若要构建一个最简单的wxPython程序,则至少需要一个应用(wx.App)对象和一个窗口(wx.Frame)对象。


通过Python指令在命令提示符窗口中运行文件。

运行并输出结果,弹出如下窗口。

自定义窗口类

在窗口中添加控件

我们在窗口中添加两个控件:一个面板(Panel)和一个静态文本(StaticText)。面板是一个没有标题栏的容器(可以容纳其他控件的控件)。

事件处理

图形界面的控件要响应用户的操作,就必须添加事件处理机制。事件处理的过程如下图所示。

其中涉及的主要内容如下。

1 事件源:事件发生的场所,就是各个控件,例如按钮事件的事件源是按钮。

2 事件:wxPython中的事件被封装为事件类wx.Event及其子类,例如按钮事件类是wx.CommandEvent,鼠标事件类是wx.MoveEvent。

3 事件处理程序:一个响应用户事件的方法。下面通过一个示例介绍事件处理流程。在以下窗口中有一个按钮和一个静态文本,在单击OK按钮时会改变静态文本显示的内容。

下面通过一个示例介绍事件处理流程。在以下窗口中有一个按钮和一个静态文本,在单击OK按钮时会改变静态文本显示的内容。

布局管理

wxPython提供了布局管理器类帮助实现界面布局,主要分为两大类:盒子布局管理器和网格布局管理器。盒子布局类似于CSS中的弹性布局,非常灵活,我们重点介绍盒子布局。

盒子布局管理器

盒子布局管理器类是wx.BoxSizer,Box布局管理器是最常用的布局管理器,它可以让其中的子窗口(或控件)沿垂直或水平方向布局。

1 创建盒子布局管理器对象

我们使用wx.BoxSizer类创建盒子布局管理器对象,主要的构造方法如下:

设置为水平方向布局,

设置为垂直方向布局。
wx.HORIZONTAL是默认值,可以省略

2 添加子窗口(或控件)到父窗口

我们使用wx.BoxSizer对象的Add( )方法添加子窗口(或控件)到父窗口,对Add( )方法的语法说明如下:

添加到父窗口

proportion参数用于设置当前子窗口(或控件)在父窗口中所占的空间比例;flag参数是布局标志,用来控制对齐方式、边框和调整尺寸;border参数用于设置边框的宽度。

下面重点介绍flag标志,flag标志可以分为对齐、边框和调整尺寸。

flag对齐标志如下表所示。

flag边框标志如下表所示。

flag调整尺寸标志如下表所示。

重构事件处理示例

盒子布局管理器嵌套示例


在本例中采用了嵌套布局,首先将两个按钮(b1和b2)放到一个水平方向的盒子布局管理器对象(hbox)中,然后将一个静态文本(statictext)和hbox放到一个垂直方向的盒子布局管理器对象(vbox)中。

控件

wxPython的所有控件都继承自wx.Control类。之前的示例已经使用了静态文本和按钮,本节重点介绍文本输入控件、单选按钮、复选框、列表和静态图片控件。

文本输入控件

文本输入控件(wx.TextCtrl)是可以输入文本的控件。

复选框和单选按钮

多选控件是复选框(wx.CheckBox),复选框(wx.CheckBox)有时也能单独使用,能提供两种状态的开和关。

单选控件是单选按钮(wx.RadioButton),同一组的多个单选按钮应该具有互斥性,就是当一个按钮按下时,其他按钮一定释放。

在界面中实现一组复选框和一组单选按钮。



列表

对列表控件可以进行单选或多选,列表控件类是wx.ListBox。

在界面中实现以下两个列表控件。



wx.LB_SINGLE:单选。
wx.LB_MULTIPLE:多选。
wx.LB_EXTENDED:多选,但是需要在按住Ctrl或Shift键时选择项目。
wx.LB_SORT:对列表选择项进行排序。

静态图片控件

静态图片控件用于显示一张图片,图片可以是wx.Python所支持的任意图片格式,静态图片控件类是wx.StaticBitmap。

在界面中实现两个按钮和一个静态图片控件,在单击按钮时显示不同的图片。

网络通信

基本的网络知识

TCP/IP

在网络通信中会用到一些相关协议,其中,TCP/IP是非常重要的协议,由IP和TCP两个协议构成。IP(Internet Protocol)是一种低级的路由协议,它将数据拆分在许多小的数据包中,并通过网络将它们发送到某一特定地址,但无法保证所有包都抵达目的地,也不能保证包按顺序抵达。

由于通过IP传输数据存在不安全性,所以还需要通过TCP(Transmission Control Protocol,传输控制协议)进行网络通信。TCP是一种高层次的协议,是面向连接的可靠数据传输协议,如果有些数据包没被收到,则会重发,对数据包的内容准确性进行检查并保证数据包按顺序抵达。所以,TCP能够保证数据包安全地按照发送时的顺序送达目的地。

IP地址

为了实现网络中不同计算机之间的通信,每台计算机都必须有一个与众不同的标识,这就是IP地址,TCP/IP使用IP地址来标识源地址和目的地址。

最初,所有的IP地址都是由32位数字构成的,由4个8位的二进制数组成,每8位之间用圆点隔开,例如192.168.1.1,这种类型的地址通过IPv4指定。现在有一种新的地址模式,叫作IPv6,IPv6使用128位数字表示一个地址。尽管IPv6比IPv4有很多优势,但是由于习惯的问题,很多设备还是采用IPv4。

另外,我们有时还会用到一个特殊的IP地址127.0.0.1,127.0.0.1叫作回送地址,指本机。回送地址主要用于网络软件测试及本机的进程间通信,只发送数据,只进行本机进程间通信,不进行任何网络传输。

端口

一个IP地址标识一台计算机,每一台计算机又有很多网络通信程序在运行,提供网络服务或进行通信,这就需要不同的端口进行通信。如果把IP地址比作电话号码,那么端口就是分机号码,在进行网络通信时不仅要指定IP地址,还要指定端口号。

TCP/IP系统中的端口号是一个16位的数字,它的范围是0~65535。将小于1024的端口号保留给预定义的服务,例如HTTP是80,FTP是21,Telnet是23,Email是25,等等。除非要和那些服务进行通信,否则不应该使用小于1024的端口。

HTTP/HTTPS

对互联网的访问大多基于HTTP/HTTPS,HTTP/HTTPS是TCP/IP的一种协议。

1 HTTP
HTTP(Hypertext Transfer Protocol,超文本传输协议)属于应用层协议,其简捷、快速的方式适用于分布式超文本信息传输。HTTP是无连接协议,即在每一次请求时都建立连接,服务器在处理完客户端的请求后,会先应答客户端,然后断开连接,不会一直占用网络资源。

HTTP/1.1共定义了8种请求方法:OPTIONS、HEAD、GET、POST、PUT、DELETE、TRACE和CONNECT。GET和POST方法最常用。

1)GET方法:用于向指定的资源发出请求,被发送的信息“显式”地跟在URL后面。它一般只用于读取数据,例如静态图片等。GET方法有点像使用明信片给别人写信,将“信的内容”写在外面,接触到的人都可以看到,因此是不安全的。

2)POST方法:用于向指定的资源提交数据,请求服务器进行处理,例如提交表单或者上传文件等。数据被包含在请求体中。POST方法像是把“信的内容”装入信封中,接触到该信封的人都看不到信的内容,因此是相对安全的。

2 HTTPS
HTTPS(Hypertext Transfer Protocol Secure,超文本传输安全协议)是超文本传输协议和SSL的组合,用于提供加密通信及对网络服务器身份的鉴定。简单地说,HTTPS是加密的HTTP。

HTTPS与HTTP的区别是:HTTPS使用https://代替http://,HTTPS使用端口443,而HTTP使用端口80与TCP/IP通信。

搭建自己的Web服务器

搭建Web服务器的步骤如下。

1 安装JDK(Java开发工具包)
我们的Web服务器是Apache Tomcat,是支持Java Web技术的Web服务器。Apache Tomcat的运行需要Java运行环境,而JDK提供了Java运行环境,因此我们首先需要安装JDK。

2 配置Java运行环境
Apache Tomcat在运行时需要用到JAVA_HOME环境变量,因此需要先设置JAVA_HOME环境变量。

首先,打开Windows系统环境变量设置对话框,打开该对话框有很多方式,如果是Windows 10系统,则在桌面上用鼠标右键单击“此电脑”图标,弹出Windows系统对话框,之后如下图所示操作。


3 安装Apache Tomcat服务器
我们可以从本章的配套代码中找到Apache Tomcat安装包apache-tomcat-9.0.13.zip,只需将apache-tomcat-9.0.13.zip解压即可安装Apache Tomcat服务器。

4 启动Apache Tomcat服务器
在Apache Tomcat解压目录的bin目录下找到startup.bat文件,双击startup.bat即可启动Apache Tomcat。

启动Apache Tomcat成功后会看到如下信息。

5 测试Apache Tomcat服务器
打开浏览器,在地址栏中输入http://localhost:8080/NoteWebService/,在打开的页面上介绍了当前Web服务器已经安装的Web应用(NoteWebService)的具体使用方法。

打开浏览器,在地址栏中输入网址http://localhost:8080/NoteWebService/note.do,在打开的页面上可以查询所有数据。

urllib.request模块

发送GET请求

如果要发送HTTP/HTTPS的GET请求,则可以使用urllib.request模块的Request对象。

示例:

发送POST请求

如果要发送HTTP/HTTPS的POST请求,则其发送流程与发送GET请求非常类似。

示例:

JSON数据

JSON文档的结构

构成JSON文档的两种结构为:JSON对象(object)和JSON数组(array)。

1 JSON对象
JSON对象类似于Python中的字典类型。

2 JSON数组
JSON数组类似于Python中的列表类型,示例如下:

我们使用json模块提供的loads(str)函数进行JSON数据的解码,参数str是JSON字符串,返回Python数据。

JSON数据的解码

JSON数据的解码(decode)指将JSON数据转换为Python数据,当从网络中接收或从磁盘中读取JSON数据时,需要将其解码为Python数据。

在编码过程中,JSON数据被转换为Python数据。

示例:

下载图片示例



在文件下载成功后,会在当前目录下看到download.png文件。

访问数据库

如果数据量较少,则我们可以将数据保存到文件中;如果数据量较大,则我们可以将数据保存到数据库中。

SQLite数据库

SQLite是嵌入式系统使用的关系数据库,目前的主流版本是SQLite 3。SQLite是开源的,采用C语言编写而成,具有可移植性强、可靠性高、小而易用等特点。SQLite提供了对SQL-92标准的支持,支持多表、索引、事务、视图和触发。

SQLite数据类型

SQLite是无数据类型的数据库,在创建表时不需要为字段指定数据类型。但从编程规范上讲,我们应该指定数据类型,因为数据类型可以表明这个字段的含义,便于我们阅读和理解代码。

SQLite支持的常见数据类型如下。

INTEGER:有符号的整数类型。
REAL:浮点类型。
TEXT:字符串类型,采用UTF-8和UTF-16字符编码。
BLOB:二进制大对象类型,能够存放任意二进制数据。

Python数据类型与SQLite数据类型的映射

在使用Python访问SQLite数据库时,会经常涉及数据类型的互相转换。它们的映射关系如下表所示。

使用GUI管理工具管理SQLite数据库

1 安装和启动DB Browser for SQLite
从本章配套代码中找到DB.Browser.for.SQLite-3.11.2-win32.zip安装包文件,将该文件解压到一个目录中,在解压目录下找到DB Browserfor SQLite.exe文件,双击该文件即可启动DB Browser for SQLite工具。

2 创建数据库
一个SQLite数据库对应一个SQLite数据文件,为了测试DB Browserfor SQLite工具,我们要先创建SQLite数据库。
在上图所示的界面单击工具栏中的“新建数据库”按钮,弹出保存文件对话框。

3 创建数据表
在一个SQLite数据库中可以包含多个数据表。在上图所示的界面单击“保存”按钮,弹出建表对话框。

4 执行SQL语句
使用DB Browser for SQLite工具,可以执行任意合法的SQL语句。

5 浏览数据
DB Browser for SQLite常用于浏览数据。

数据库编程的基本操作过程

数据库编程主要分为两类:查询(Read)和修改(C插入、U更新、D删除)。
1 查询数据
查询数据时需要6步,在查询过程中需要提取数据结果集,最后释放资源,即关闭游标和数据库。

2 修改数据
修改数据时如上图所示,最多需要6步,在修改过程中如果执行SQL操作成功,则提交数据库事务;如果失败,则回滚事务。最后释放资源,关闭游标和数据库。

sqlite3模块API

Python官方提供了sqlite3模块来访问SQLite数据库。

数据库连接对象Connection

数据库访问的第一步是进行数据库连接。
我们可以通过connect(database)函数建立数据库连接,参数database是SQLite数据库的文件路径,如果连接成功,则返回数据库连接对象Connection。
Connection对象有如下重要的方法。

close( ):关闭数据库连接,在关闭之后再使用数据库连接将引发异常。
commit( ):提交数据库事务。
rollback( ):回滚数据库事务。
cursor( ):获得Cursor游标对象。

游标对象Cursor

一个Cursor游标对象表示一个数据库游标,游标暂时保存了SQL操作所影响到的数据。游标是通过数据库连接创建的。

游标Cursor对象有很多方法和属性,其中的基本SQL操作方法如下。
execute(sql[,parameters]):执行一条SQL语句,sql是SQL语句,parameters是为SQL提供的参数,可以是序列或字典类型。返回值是整数,表示执行SQL语句影响的行数。

executemany(sql[,seq_of_params]):执行批量SQL语句,sql是SQL语句,seq_of_params是为SQL提供的参数,seq_of_params是序列。返回值是整数,表示执行SQL语句影响的行数。

在通过execute( )和executemany( )方法执行SQL查询语句后,还要通过提取方法从查询结果集中返回数据,相关提取方法如下。

fetchone( ):从结果集中返回只有一条记录的序列,如果没有数据,则返回None。

fetchmany(size=cursor.arraysize):从结果集中返回小于等于size记录数的序列,如果没有数据,则返回空序列,size在默认情况下是整个游标的行数。

fetchall( ):从结果集中返回所有数据。

数据库的CRUD操作示例

对数据库表中的数据可以进行4类操作:数据插入(Create)、数据查询(Read)、数据更新(Update)和数据删除(Delete),即增、删、改、查。

示例中的数据表

为了查询方便,我们预先插入几条记录。


在输入SQL语句后,单击该按钮执行所有SQL语句

无条件查询

SQL查询语句是SELECT,根据是否带有WHERE子句,分为:无条件查询和有条件查询,本节先介绍无条件查询。
无条件查询最为简单,没有WHERE子句。

示例:

有条件查询

有条件查询带有WHERE子句,WHERE子句是查询条件。

插入数据

数据插入操作SQL语句是INSERT。

示例:


数据插入成功,可以使用DB Browser for SQLite浏览数据。

更新数据

数据更新操作SQL语句是UPDATE。

示例:

数据更新成功,可以使用DB Browser for SQLite浏览数据。

删除数据

数据删除操作SQL语句是DELETE。

示例:

数据更新成功,可以使用DB Browser for SQLite浏览数据。

删除数据

数据删除操作SQL语句是DELETE。

示例:

数据更新成功,可以使用DB Browser for SQLite浏览数据。

多线程

如果想让我们的程序同时执行多个任务,就需要使用多线程技术了。

线程相关的知识

进程

一个进程就是一个正在执行的程序,每一个进程都有自己独立的一块内存空间、一组系统资源。在进程的概念中,每一个进程的内部数据和状态都是完全独立的。
在Windows操作系统中,一个进程就是一个exe或者dll程序,它们相互独立,相互也可以通信。

线程

在一个进程中可以包含多个线程,多个线程共享一块内存空间和一组系统资源。所以,系统在各个线程之间切换时,开销要比进程小得多,正因如此,线程被称为轻量级进程。

主线程

Python程序至少有一个线程,这就是主线程,程序在启动后由Python解释器负责创建主线程,在程序结束后由Python解释器负责停止主线程。
在多线程中,主线程负责其他线程的启动、挂起、停止等操作。其他线程被称为子线程。

线程模块——threading

Python官方提供的threading模块可以进行多线程编程。threading模块提供了多线程编程的高级API,使用起来比较简单。
在threading模块中提供了线程类Thread,还提供了很多线程相关的函数,这些函数中常用的如下。

active_count( ):返回当前处于活动状态的线程个数。
current_thread( ):返回当前的Thread对象。
main_thread( ):返回主线程对象。主线程是Python解释器启动的线程。

示例:

创建子线程

创建一个可执行的子线程,需要如下两个要素。
1 线程对象:线程对象是threading模块的线程类Thread或Thread子类所创建的对象。
2 线程体:线程体是子线程要执行的代码,这些代码会被封装到一个函数中。子线程在启动后会执行线程体。实现线程体主要有以下两种方式。

1)自定义函数实现线程体。
2)自定义线程类实现线程体。

自定义函数实现线程体

创建线程Thread对象的构造方法如下:

target参数指向线程体函数,我们可以自定义该线程体函数;通过name参数可以设置线程名,如果省略这个参数,则系统会为其分配一个名称;args是为线程体函数提供的参数,是一个元组类型。

示例:

自定义线程类实现线程体

另外一种实现线程体的方式是,创建一个Thread子类并重写run( )方法,run( )方法就是线程体函数。

示例:

线程管理

线程管理包括线程创建、线程启动、线程休眠、等待线程结束和线程停止,其中,线程创建、线程启动和线程休眠在16.3节已经用到了,这些不再赘述。本节重点介绍等待线程结束和线程停止的内容。

等待线程结束

有时,一个线程(假设是主线程)需要等待另外一个线程(假设是t1子线程)执行结束才能继续执行。

join( )方法的语法如下:

参数timeout用于设置超时时间,单位是秒。如果没有设置timeout,则可以一直等待,直到结束。

示例:

从运行结果来看,在子线程t1结束后,主线程才输出变量value的内容,这说明主线程被阻塞了。
如果尝试将t1.join( )语句注释掉,则输出结果如下:

从运行结果可见,子线程t1还没有结束,主线程就输出变量value的内容了。

线程停止

在线程体结束时,线程就停止了。但在某些业务比较复杂时,会在线程体中执行一个“死循环”。线程体是否持续执行“死循环”是通过判断停止变量实现的,“死循环”结束则线程体结束,线程也就结束了。
另外,在一般情况下,死循环会执行线程任务,然后休眠,再执行,再休眠,直到结束循环。

示例:

下载图片示例

这个网络爬虫程序每隔一段时间都会执行一次下载图片任务,在下载任务完成后,休眠一段时间再执行。这样反复执行,直到爬虫程序停止。

示例:

posted @ 2022-01-13 10:09  20212305杨贯宇  阅读(1231)  评论(0编辑  收藏  举报