Python基础

简介

人生苦短,我用Python。

Python是一种面向对象的解释型开源免费的计算机程序设计语言,在人工智能、大数据、科学计算、金融、Web开发、系统运维等领域,有数量庞大且功能相对完善的标准库和第三方库,通过对库的调用,能够快速实现不同领域业务的应用开发。

Python设计哲学

  • 优雅
  • 明确
  • 简单

优点

  • 代码量小
  • 维护成本低
  • 编程效率高
  • 简单、易读易懂

Python的变量与数据类型

变量

变量:被实现为内存地址的符号名称,该内存地址存储了某一种数据类型的数据。

创建变量

Python中不需要声明变量,可以直接考虑一个名称,然后将其当做变量。

1
height = 1
  • 创建一个类型为整形,值为1的对象。
  • 创建一个变量名”height”
  • 把变量名关联到这个对象中

改变变量的引用

1
2
3
4
5
if __name__ == '__main__':
height = 12
print(id(height))
height = "高度"
print(id(height))

Python变量是对对象的引用,但实际数据包含在对象中。可以随时改变对对象的引用。

每个对象的创建时都会有一个唯一的标识(id),使用id()可以检查变量引用对象的标识。若表示改变则表明该对象的引用对象已经改变了。

image-20221110205246961

“=”在Python中的意义:引用赋值

“=”在C语言中是值赋值。

int x = 5;在C语言中意思是首先创建一个整形变量x,将 5的值赋值给x。

而在Python中这条语句的意思是把变量x与整数类型对象5关联起来,变量x里面存的是对对象5的引用。

对象的类型、标识和值

  • 标识:唯一不可以改变,内存地址
  • 类型:不可以改变。对象的类型确定了对象的操作,同时也定义了该种对象的取值范围
  • 值:值可以改变的对象称为可变的对象,例如列表、字典、集合;一旦创建完成值就不能改变的对象称为不可变的对象,例如整数、字符串、元组。
1
type()可以查看对象的类型,运算符is可以判断两个变量是否关联到同一个对象上,==判断连个对象的值是否相等。
1
2
3
4
5
6
7
8
9
10
11
if __name__ == '__main__':
a = 12
b = 12
print(type(a))
print(a is b)
print(a == b)

输出:
<class 'int'>
True
True

注意

Python会把值较小的对象放在缓存区。当新建一个变量要关联到“小对象”时。Python会先查找缓存区,若该“小对象”已经创建,则不会创建新的存储至值相同的对象,而是直接把这个小对象关联到新建的变量。可以使用id()方法证明。

较小的对象有:

  • 取值在[-5,256]的整数类型对象
  • 只有一个单词的字符串类型对象
  • None对象
  • 值为False/True常量的布尔类型对象

Python标识符命名约定

标识符的命名可以由大写字母A-Z,小写字母a-z,下划线”_”和数字0至9组成,但不能是Python的关键字

  • 变量名、函数名、公共方法名(public method)、公共属性名(public attribute)、软件包(packge)和模块(module)名通常遵循lowercase风格,即全部用小写,单词之间用下划线隔开。
  • 常量名必须全部用大写,单词之间用下划线隔开。
  • 类名用UpperCaseCamelCase风格,即所有单词首字母大写单词之间不用隔开。
  • 名称前面加单下划线是为了向其他程序员表明该属性或方法是私有的或者是模块内部的。”from···import *”语句不会导入名字前面有单下划线的对象。
  • 名称前面和后面加双下划线,说明这是Python系统定义和使用的属性或方法,不希望程序员去访问

代码块与缩进

PEP8定义每个缩进级别使用4个空格。

数值类型

  • 整数类型(int)
  • 布尔类型(bool)
  • 浮点数类型(float)
  • 复数类型(complex)

整数类

Python中可以通过函数将整数值进行进制转换成字符串

1
2
3
4
str()	# 转十进制
oct() # 转八进制
hex() # 转十六进制
bin() # 转二进制

通过int() 可以将各进制字符串转换为整数数值,但要加上转换字符的进制数。

1
2
3
4
if __name__ == '__main__':
num = 12p
num_str = hex(num)
print(type(int(num_str, 16)))

浮点数类型

Pyhotn的浮点数默认是双精度类型数,占8个字节的内存空间,可以提供17位有效数字。

可以通过语句sys.float_info查询浮点数的最大值和最小值。

1
2
3
if __name__ == '__main__':
num = sys.float_info.min
print(num)

布尔型

本质为整数类的一个子集,取值只有两个,一个是True,一个是False,注意第一个子母要大写

复数类

与数学上的复数定义一致,复数类由实部和虚部的二元有序实数对构成,在Python中的虚数部位单位为j。

创建复数的方法:

  • 直接键入复数:1 + 2j
  • 用complex(): complex(1,2)或complex(‘1+2j’) 注意:这里的’+’前后不能有空格

内置数值运算

特殊的:

运算符 作用 范例 结果
// 整除(向下取整) 10/3 3
** 指数运算 3 ** 3 27
abs(x) 取绝对值 abs(-10) 10
divmod(x, y) 取模 divmod(10, 3) (3, 1)
power(x , n) x的n次幂 power(3, 3) 27

布尔运算

Python内置的布尔运算符有与(and)、或(or)、非(not)

比较运算

Python内置的运算有大于,小于,等于,is,is not等。

特殊的有:

运算符 作用 范例 结果
is 判断两个对象是否一致 5 is 5 True
is not 判断两个对象是否不一致 5 is not 5 False

is 与 == 的区别:is判断的是两个变量引用的对象是否为同一个相当与判断两个对象的id是否一致。但==判断的是两个对象的值是否一致。

整数按位运算

位运算符 说明 使用形式 举 例
& 按位与 a & b 4 & 5
| 按位或 a | b 4 | 5
^ 按位异或 a ^ b 4 ^ 5
~ 按位取反 ~a ~4
<< 按位左移 a << b 4 << 2,表示整数 4 按位左移 2 位
>> 按位右移 a >> b 4 >> 2,表示整数 4 按位右移 2

Python中数值一般用补码来表示。

正整数的补码是对应的二进制码,负整数的补码是其对应的正整数二进制按位取反,然后加1.

例:5的补码是0b00000101,-6的补码是0b11111010,所以5按位取反的结果是6。

按位运算的比较级低于数值运算,但高于比较运算。

字符串

字符串属于Python最基本的数据结构:序列(sequence).

创建字符串

在Python中可以用单引号、双引号和三引号创建字符串

1
2
3
strs = "koko"
str1 = 'Hello word'
str1 = """Hellow"""

三者的区别

为了维持Python语言的美丽以及简单,三者可以嵌套使用,可以减少转义字符的出现。

使用单引号和双引号定义字符串时,若遇到字符串有多行时,需要在每行的后面加多一个换行的转义字符”\n”,但使用三引号则不需要(注意在换行时新的一行前面输入的空格也会输出)

1
2
3
4
5
6
7
8
9
10
11
12
13
# 常规的换行
msg = \
"hello,everyone!"\
"this is Bob"
print(msg)

# Python中更加优雅的换行 小括号 + 单引号或双引号
msg = (
"Hello,Everyone!"
"This is Alex,Nice to meet you!"
)

注意这里的换行不会输出,每行的字符串会拼接在一起。

索引

Python字符串中的元素可以用下标进行索引,并且可以从两个方向进行索引。

image-20221111101528795

解包:

字符串可以通过解包获得字符。

1
2
3
4
5
6
7
8
9
10
if __name__ == '__main__':
x, y, z = "abc"
print(x)
print(y)
print(z)

输出:
a
b
c

字符串与数值类一样,都是不可变对象,不可以根据索引修改字符串的值。

字符串切片

使用[ ]除了可以获取单个字符外,还可以指定一个范围来获取多个字符,也就是一个子串或者片段,具体格式为:

strname[start : end : step]

对各个部分的说明:

  • strname:要截取的字符串;
  • start:表示要截取的第一个字符所在的索引(截取时包含该字符)。如果不指定,默认为 0,也就是从字符串的开头截取;
  • end:表示要截取的最后一个字符所在的索引(截取时不包含该字符)。如果不指定,默认为字符串的长度;
  • step:指的是从 start 索引处的字符开始,每 step 个距离获取一个字符,直至 end 索引出的字符。step 默认值为 1,当省略该值时,最后一个冒号也可以省略。

连接和重复

  • “字符串+字符串”实现字符串连接。
  • “字符串*n”实现字符串重复n次
1
2
3
4
5
msg1 = 'Hello '
msg2 = 'world!'
msg3 = msg1 +msg2
msg3 = msg3 * 10

获取字符串长度、最大、最小元素

1
2
3
4
s = "Hello,world!"
print(min(s))
print(max(s))
print(len(s))

常用的方法可以查看官方文档:

Python 官方文档 官方文档|官方教程|Python 官方文档 API中文手册|Python 官方文档参考文档_w3cschool

函数和方法

  • 方法属于类的一个成员,在类中定义;调用时,方法名前面需要加类名或对象名。
  • 函数独立定义,不属于某个类,调用时直接使用函数名。

dir()和help()函数

  • 使用dir函数查看某种类的属性和方法
  • 使用help函数查看某种方法或函数怎么使用

print函数

可以查看:http://t.csdn.cn/jqcPu

f字符串

使用f字符串可以实现字符串的格式化,

在字符串前面加入一个前缀f,然后用{}括号表示替换的对象。

1
2
3
4
first_name = "ada"
last_name = "smith"
msg = f"Hello,{first_name}{last_name}"
print(msg)

input函数

原型:input([prompt])其中prompt是提示文字,提示用户输入信息的要求。

1
2
3
num1 = input("请输入一个数字")
num2 = input("请输入一个数字")
print(num1 + num2)

eval()函数

eval()函数可以直接计算字符串型数学表示的值,可以与input()函数一起使用计算数学表达式的值。

列表

列表允许任意Python类型的元素组合在一起。

特点:

  • 有序化:列表的元素被有序的组合在一起。

  • 可以包含任意类型的对象。

  • 列表的元素可以通过索引访问,可迭代,可遍历。

  • 支持自动解包。

  • 列表可以嵌套,在列表中可以有列表。

  • 列表的大小是可变的。

  • 列表是可变对象,元素可以增加、更改或删除。

  • 创建

可以利用list()函数和[]创建。

  • list()函数:只能输入一个可迭代对象,然后把可迭代对象的元素加入列表。
  • 方括号[]:可以输入多个对象,把输入对象作为元素整体加入列表。
1
2
3
4
5
6
7
8
9
   list1 = list("Hello word")
print(list1)
list2 = ["Hello word", "bob"]
print(list2)


输出:
['H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'd']
['Hello word', 'bob']

在[]中的可迭代对象前面加上’*’可以对对象进行解包。

1
2
3
4
5
list2 = [*"Hello word", "bob"]
print(list2)

输出:['H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'd', 'bob']

列表解包

把元素从列表中取出有解包、索引和切片等方式。

解包:将可迭代对象中的元素取出逐个分发给对应的变量。

1
2
3
4
5
6
7
8
9
10
11
12
   list1 = ["Hello World", "Bob", "Alex"]
a, b, c = list1
print(a)
print(b)
print(c)


输出:
Hello World
Bob
Alex

应用:

使用*号解包列表,其元素作为输入参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def dem_unpacking(a, b, c):
print(a)
print(b)
print(c)

if __name__ == '__main__':
list1 = ["Hello World", "Bob", "Alex"]
a, b, c = list1
dem_unpacking(*list1)


输出:
Hello World
Bob
Alex

当变量个数少于元素个数时,在其某个元素上加上’*’号,意思是接受剩余的所有元素。

1
2
3
4
5
6
7
8
9
10
   list1 = ["Hello World", "Bob", "Alex", "John"]
a, *b, c = list1
print(a)
print(b)
print(c)

输出
Hello World
['Bob', 'Alex']
John

索引

列表的索引和字符串对象的一致,有两个方向。但列表为可变对象可以根据索引进行修改、增加和删除。

切片

列表的切片与字符串对象的切片一致

列表的基本操作

常用的操作可以查看链接:Python 列表(List) | 菜鸟教程 (runoob.com)

列表的拷贝

  • 引用拷贝
  • 浅拷贝
  • 深拷贝

引用拷贝

使用“=”实现的就是引用拷贝,例如list1 = list2,就是一个引用拷贝,两个变量都关联到了同一个列表对象上。

浅拷贝

列表的浅拷贝指在内存中新建一个原列表对象的副本,并把新建的列表变量关联到原列表的元素对象上,但不会在内存中新建一份原列表的元素对象

image-20221111214017900

新建元素的元素地址不变。

深拷贝

将所有元素都复制一份新的给新建变量。使用copy模板中的**deepcopy()**函数实现。

微信图片_20221111214426(1)

元组

元组跟列表一样,也是一个序列型。但元组一但创建成功就不能对其进行增加、更改和删除。

元组特点:

  • 元组在运行速度和空间上都优于列表
  • 若知道那些数据不必修改,用元组比用列表好,以为可以保护数据意外更改。
  • 元组的元素可以通过索引访问,可迭代、可遍历。
  • 元组支持自动解包。
  • 元组可以任意嵌套
  • 元组一旦创建不可以更改
  • 一个方法或函数要返回多个值时,元组是一个不错的选择。

创建元组

使用tuple()函数或小括号创建元组。

  • tuple()函数:只能输入一个可迭代对象,然后把可迭代对象的元素加入元组。
  • 小括号():可以输入多对象,把输入的对象作为整体加入元组。

元组的解包,索引、切片与列表一致。

注意的是:解包时接受剩余元素的数据类型是列表

常用函数

参考:Python 元组 | 菜鸟教程 (runoob.com)

zip函数

zip()函数可以将多个可迭代对象中的元素组成元组,并返回zip对象(类似map)。用list()函数又可以将zip对象转换为列表。

1
2
3
4
5
6
if __name__ == '__main__':
list1 = ["Hello World", "Bob", "Alex", "John"]
tu = tuple(list1)
z = zip(list1, tu)
l = list(z)
print(l)

字典

字典类是一种基础元素为”键-值对”,无序可变,可嵌套可迭代的数据结构。

特点:

  • 基础元素为”键-值对”,通过键名而不是索引号来索引访问值。
  • 字典中的元素是无序的,不能通过索引访问。
  • 字典中元素的访问速度远高于列表和元组。
  • 字典可变,元素可以增加、更改和删除。
  • 支持自动解包。
  • 可以任意嵌套。
  • 键不可以重复。会记录最新的键。
  • 空字典用大括号表示。
  • 键必须是不可变的数据类型。因为在Python中只用不可变的数据类型才能哈希化。(可以通过_hash_()方法查阅数据类型是否可以哈希化,不能哈希化的数据类型会返回NoneType)

创建

字典用大括号定义,用”:”将键和值分开,键值对之间用逗号隔开。也可以用dict()定义。

1
2
3
4
5
6
d = {1: 'mian', 2: 'hello', 3: 'world'}
print(d)
key_list = [1, 2, 3, 4]
value_list = ['Hello', 'world', 'I`m', 'Bob']
d1 = dict(zip(key_list, value_list))
print(d1)

访问字典的值

  • 字典规定通过方括号和键来访问值,若键不存在会报错,也可以通过方括号和键加上赋值语句来添加修改字典元素;通过方括号和键名加del()函数删除元素。

  • 为了防止访问的键名不存在而报错,可以通过get(key,default = None)返回默认值。

  • 使用items()方法可以返回可迭代对象。

1
2
3
4
5
d = {1: 'mian', 2: 'hello', 3: 'world'}
del(d[1])
d_items = d.items()
for key, value in d_items:
print(key, value)

字典解包

  • 解包后赋值变量:解包后仅把键名传给变量。
  • 解包后作为参数传递给函数:单”*”表示解包后把键名作为参数传递给函数,键名个数与形参个数相同;双星号’**’表示把键值作为参数传递给函数,函数形参名需与键名相同。

字典基本操作

可参阅:Python 字典(Dictionary) | 菜鸟教程 (runoob.com)

集合

定义:数学中最基本的概念之一,指定义明确的不同对象的聚集。

集合的基本操作包括交集、并集、补集等。(补集一般指绝对补集,即一般地,设S是一个集合AS的一个子集,由S中所有不属于A的元素组成的集合,叫做子集AS中的绝对补集。)

集合类是无序且没有重复元素、可变、可迭代的数据类型。集合的底层是由字典实现的。,所以在集合上进行检查成员资格操作”in”也远远快于在列表和元组上。

特点

  • 集合中的元素唯一。
  • 集合中的元素无序,不能通过下标访问。
  • 集合对象可变、可迭代。
  • 集合只能接受不可变的数据类型作为元素。
  • 集合常用于高效找出两个数据集中的共同点和差异点。

集合中有一种特殊的集合:冻结集合(frozenset),它和元组一样,一但创建就不能变,其余的特性跟集合一样。

1
f = frozenset("Hello")  # 冻结集合定义

创建

使用大括号定义也可以使用set()函数定义。

  • “{}”已经解释为空字典,所以不能使用”{}”来创建空集合,只能使用set()创建空集合。
  • 当用{}创建集合时,”{}”会把输入对象作为一个集合元素,整体加入集合,所以输入对象不能是可变数据类型。
  • 使用set()函数创建集合时,set()函数会把输入对象的元素作为集合元素加入集合,所以输入对象可以是可变数据类型,但其元素必须是不可变的数据类型。符合这个条件也可以使用”{}”创建,但一定要对输入对象元素进行解包。

访问集合元素

集合通常用于高效找出两个数据集中的共同点和差异点,Python没用提供单独索引集合元素的方法。但可以通过迭代访问集合中的元素。

集合解包

集合的解包与列表一致。

集合基本操作

可以参阅:Python3 集合 | 菜鸟教程 (runoob.com)

列表、元组、字典和集合的区别

类别 定义符号 是否可变 元素是否可变 是否有序 是否可迭代
列表(list) [元素1, 元素2] 可变 可变 有序 可迭代
元组(tuple) (元素1, 元素2) 不可变 不可变 有序 可迭代
字典(dict) {键1:值1, 键2:值2} 可变 键:不可变 值:可变 无序 可迭代
集合(set) {元素1, 元素2} 不可变 不可变 无序 可迭代

Python中的可变对象与不可变对象

  • 可变对象:列表、字典、集合、字节数组、用户定义的类
  • 不可变对象:整数、浮点数、十进制数、复数、布尔值、字符串、元组、范围类、冻结集合、字节类。

流程控制语句

if条件语句

image-20221112120214362

使用格式

1
2
3
4
5
6
7
8
9
10
11
12
13
num1 = 12
if num1 < 45:
print(num1, "小于", 45)
else:
print(num1, "大于", 45)

# 多重if···elif···else
if num1 > 45:
print(num1, "大于", 45)
elif 10 <= num1 <= 45:
print(num1, "在", 10, "和", 45, "之间")
else:
print("当所有条件都不符合时执行本语句块")

使用布尔运算符连接多个条件

  • 同时满足多个条件,使用and将条件连接。
1
2
3
4
5
6
if num1 < 45 and num1 > 10:
print(num1, "在", 12, "和", 45, "之间")

可以简化为:
if 10 < num1 < 45:
print(num1, "在", 12, "和", 45, "之间")
  • 只需要满足多条件中的一个,使用or连接语句
1
2
if num1 < 45 or num1 < 20:
print("test")

not操作符

在Python中False,None、空字符串、空列表、空元组、空字典等都相当于False,not与这些变量结合,会返回True。

三元运算

Python不支持”:?”运算符,所以只能使用if语句实现。

while循环语句

image-20221112152859388

while语句 while···else语句
while 条件表达式:
语句块
while 条件表达式:
语句块1
else:
语句块2
1
2
3
4
5
while num1 > 10:
print(num1)
num1 -= 1
else:
print(num1, "已经到达极限")

break和continue语句

使用break可以跳出本循环,使用continue可以跳出本次循环,开始下一轮循环。

for循环语句

与while相比for循环语句属于计次循环,不容易导致死循环。

类型 for语句 for···else语句
语法 for 变量 in 可迭代对象:
循环体
for 变量 in 可迭代对象:
循环体
if 条件语句:
break
else:
语句
范例 for i in range(10):
print(i)
for i in range(10):
print(i)
if i == 5:
break
else: print(‘到此结束byebye’)

range()函数与for循环

range(start, end, step)生成一个左闭右开的步长为step的序列。步长可以省略,默认为一。

具体可以查看Python3 循环语句 | 菜鸟教程 (runoob.com)

列表推导式

在Python中可以将列表和for循环语句组合在一起形成列表推导式,只用一行就可以表达一组元素。

  • 列表推导的语法格式如下:
1
列表变量 = [表达式 for 循环变量 in 可迭代对象]

eg:生成1到10的平方的列表。

1
2
3
4
5
list1 = [x ** 2 for x in range(10)]
print(list1)

输出:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
  • 同时在推导式后面还可以添加if条件语句。

语法格式:

1
列表变量 = [表达式 for 循环变量 in 可迭代对象 if语句]
  • 同时列表推导式还可以嵌套
1
列表变量 = [表达式 for 循环变量1 in 可迭代对象1 for 循环变量2 in 可迭代对象2 ··· for 循环变量n in 可迭代对象n if 条件语句]

集合推导式与字典推导式一致,区别是字典推导式推导出的为”键-值对”

异常处理和try

异常

在Python中,Python解释器中报错的错误信息可以分为两大类。

  • 语法错误(syntax error),语法不正确,程序不能运行。
  • 异常错误(exception error),语法正确,在运行时Python解释器检测到了违反规则的错误。

两者的区别

从程序的实现的角度来看,语法错误不能用异常处理语句try捕捉到,但异常错误能够用异常处理语句try捕捉到。

从程序运行视角,语法错误是程序本身的错误,违反了语法规则,异常错误是由于外部条件出现的错误。

异常名称 描述
ZeroDivisionError 除(或取模)零 (所有数据类型)
IOError 输入/输出操作失败
ImportError 导入模块/对象失败
IndexError 序列中没有此索引(index)
KeyError 映射中没有这个键
MemoryError 内存溢出错误(对于Python 解释器不是致命的)
NameError 未声明/初始化对象 (没有属性)

异常处理语句

将有发生异常风险的代码块放入try语句中,当有异常发生的时候,由try语句负责捕捉异常,并对此进行处理。

语法:

1
2
3
4
5
6
7
8
9
10
11
try:
<语句> #运行别的代码
except <名字> as 标识符:
<语句> #如果在try部份引发了'name'异常
except <名字>,<数据>:
<语句> #如果引发了'name'异常,获得附加的数据
else:
<语句> #如果没有异常发生
finally:
# 不管有没有发生异常,都会执行的代码

注意

  • finally通常用于释放外部资源。
  • 若没有发生异常情况下,没有代码需要运行,则try···except···else语句块精简为try···except语句块。
  • except语句中的”as”标识符,用于获取异常错误的原因,可以省略。
1
2
3
4
try:
print(10/0)
except ZeroDivisionError as e:
print(e)

异常抛出语句:raise语句

使用raise语句可以将本函数或方法中的异常暂时抛出,等之后使用本函数或方法时在进行处理。

1
2
raise [Exception [, args [, traceback]]]

其中[Exception [, args [, traceback]]]为可选参数,用于指定抛出的异常名称以及原因。若省略,则会把当前的错误原样抛出。

1
2
3
4
5
6
try:
正常逻辑
except Exception,err:
触发自定义异常
else:
其余代码

其他异常可以参考:Python3 错误和异常 | 菜鸟教程 (runoob.com)

函数、模块和包

Python函数

定义函数

1
2
3
4
def 函数名([参数列表]):
[函数注释]
[语句块,也称为函数体]
[return 语句]

函数调用

1
函数名([参数列表]) #参数之间中逗号隔开。

参数传递

调用函数时,实参的个数与位置必须与形参一一对应,否则容易引发TypeError语法错误。

  • 缺少参数:missing xx required postional argument.
  • 参数不对应:unsupported operand type(s) for.

在Python中提供了关键字参数:

1
2
3
4
5
6
7
#可写函数说明
def printme( str ):
print (str)
return

#调用printme函数
printme( str = "函数调用")

默认参数

定义函数时,可以指定形参的默认值。需要注意的是,默认参数必须放在非默认参数的后面,否则会引发语法错误。

1
>>>SyntaxError: non-default argument follows default argument

调用函数时,若没有指定默认参数的值,函数将使用默认的值传入。

在Python中赋值给形参的值都是对象,Python对象分为可变对象和不可变对象,若赋给形参的对象为可变对象,等同于引用传递;若赋给形参的为不可变对象,等同于值传递。

不定长参数

定义函数是,参数列表需要考虑两种情况。

  • 输入参数已知,直接将参数列出即可。
  • 输入参数未知,需要用不定长参数

不定长参数语法

  • 单星号”*”,用元组类型存储调用者传递给函数的任意参数,*是必须的后面可以为任意名字。
  • 双星号”**”,用字典类型存储调用者传递给函数的任意参数,**是必须的,后面可以跟任意参数。

标准参数必须放在不定长参数前面

返回语句

返回语句可以放在函数的任意位置,返回任意值。若函数没有return语句或者return语句后面没有返回值,那么函数执行完毕之后,返回None对象。

文档字符

在Python中,文档字符串是指一行或多行字符串文字,它作为模块、函数、类或方法定义中的第一条语句出现,用于提供模块、函数、类或方法的说明。(利用help函数查阅模块、函数、类和函数的使用说明时,其返回的说明文字就是文档字符串。

文档字符串一般存储在函数的”_doc_“属性中。

文档字符串一般写在一对**’’’**中。

1
2
3
4
5
6
7
8
9
10
def list_test(num1, *list3):
'''
测试不定长参数
:param num1: 常规参数
:param list3: 不定长参数
:return:
'''
print(num1)
for i in list3:
print(i)

嵌套函数

在一个函数体内定义的函数,被称为嵌套函数,又称为内部函数;嵌套函数所在的上一层函数,被称为外层函数。嵌套函数提供一种机制,让函数可以当做对象传递。

1
2
3
4
def outer():
def inner(a, b):
return a + b
return inner

嵌套函数连同定义嵌套函数的所有外层函数,被称为闭包区域。嵌套函数可以直接访问闭包区域中的变量。

使用关键字nonlocal,告诉Pyhton解释器这是一个非局部变量,从而可以在嵌套函数中修改闭包区域中外层函数的变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def outer():
num1 = 12
def inner(a, b):
num1 = 13
print(num1)
return a + b
inner(12, 45)
print(num1)
return inner


输出:
13
12

def outer():
num1 = 12
def inner(a, b):
nonlocal num1
num1 = 13
print(num1)
return a + b
inner(12, 45)
print(num1)
return inner

输出:
13
13

匿名函数

在Python中匿名函数用lambda表达式实现。语法如下:

1
lambda [参数列表]: 表达式
1
2
x = lambda a : a + 10
print(x(5))

变量作用域

命名空间

在Python中,变量相当于一个标签,是对内存中对象的引用。当使用“=”将变量绑定到某个对象的时候,相当于建立了一个从变量名到对象的映射。Python使用命名空间记录这些映射信息。

在不同时刻创建的命名空间拥有不同的生存空间;

  • 内置命名空间,包含内置名称的空间是在Pyhton解释器启动的时候创建的,永远不会销毁。
  • 全局命名空间,全局变量的命名空间在定义该全局变量的模块被读入时创建,一般会持续到Python解释器退出。
  • 闭包命名空间,若定义了嵌套函数,则调用最外层函数时创建闭包空间,闭包区域中的所有函数执行完毕之后,闭包命名空间被销毁。
  • 局部命名空间,局部变量的命名空间在定义该局部变量的函数或方法被调用时创建,并在函数或方法返回时销毁。

变量查找顺序

假设我们要使用变量 runoob,则 Python 的查找顺序为:局部的命名空间去 -> 全局命名空间 -> 内置命名空间

如果找不到变量 runoob,它将放弃查找并引发一个 NameError 异常:

1
NameError: name 'runoob' is not defined。

global关键字

使用global关键字修饰变量,告诉编译器这是一个全局变量。如果在函数中修改全局变量,一定要使用global关键字进行声明。

1
2
3
4
5
6
7
8
9
10
def alert_num():
global number1
number1 = 321
print(number1)


# Press the green button in the gutter to run the script.
if __name__ == '__main__':
alert_num()
print(number1)

nonlocal关键字

使用nonlocal告诉解释器这是一个非局部变量,从而可以在内部函数中修改并访问这个非局部变量。

  • 非局部声明变量指代的已有标识符是最近外面函数的已声明变量,但是不包括全局变量。这个是很重要的,因为绑定的默认行为是首先搜索本地命名空间。nonlocal声明的变量只对局部起作用,离开封装函数,那么该变量就无效。
  • 非局部声明不像全局声明,我们必须在封装函数前面事先声明该变量
  • 非局部声明不能与局部范围的声明冲突
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 1 count = 1
2
3 def a():
4 count = 'a函数里面'   #如果不事先声明,那么函数b中的nonlocal就会报错
5 def b():
6 nonlocal count
7 print(count)
8 count = 2
9 b()
10 print(count)
11
12 if __name__ == '__main__':
13 a()
14 print(count)


输出:
a函数里面
2
1

Python模块

模块

从组件的角度来讲,语句是函数和类的组件,函数和类是模块的组件,模块是包的组件。

image-20221114164633599

创建模块

从程序开发的角度看,创建Pyhton模块就是编写一个.py文件,模块名就是这个文件的名字。这个文件主要包含:

  • 函数:实现函数的定义
  • 类:实现类的定义
  • 语句:导入模块时,模块中的语句会被执行,通常模块中的语句用于初始化模块。

导入模块

1
import 模块名1 [as 别名 1],模块名2 [as 别名 2]

注意:模块名不需要加上扩展名。例如导入caluclator.py

1
import caluclator

在使用import语句导入模块时,Python解释器回味模块创建一个新的命名空间,该模块的变量名、函数名、类名都包含在这个新创建的命名空间中。调用这个模块中的元素时,需要在前面加上”模块名.”。

也可以使用from···import语句直接将模块中的成员导入当前命名空间,这样就不需要在前面加上模块名。但注意导入模块之间的成员不能重复,否则后面导入的成员会覆盖掉之前导入的成员。

1
from 模块名 import 成员列表

可以使用通配符’*’,导入所有成员。

模块搜索目录

当执行import语句时,Python解释器会按照以下顺序来搜索模块:

  • 当前目录,即正在运行的Python文件所在的目录。
  • 环境变量PYTHONPATH指定的目录。
  • Python解释器的默认安装目录和标准库目录。

Python包

将多个功能上有关联的模块放到一个文件夹中,并配上一个_init_.py文件(让Python解释器区别普通文件夹和Python包),这个文件以及文件夹中所有的Python模块共同组建了Python包,文件夹的名字就是Python包的文字。

Python项目的模块化结构:

  • 一个顶层模块,及入口文件类似于C/c++的main函数。
  • 一个项目说明文件
  • 若干个包。
  • Python包中的若干个Python模块。
  • Python模块中有若干个Python函数定义、类定义和变量。

文件夹结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Foo/
|-- bin/
| |-- foo
|
|-- foo/
| |-- tests/
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py
| |-- main.py
|
|-- docs/
| |-- conf.py
| |-- abc.rst
|
|-- setup.py
|-- requirements.txt
|-- README

导入包

格式:

1
2
3
from <包名> import <模块名>[,模块名]
from <包名> import <模块名> as <别名>
from <包名> import *

安装包

开发Python程序时可能需要安装第三方的包,可以在PyPI(https://pypi.org/)中查找、安装和发布包。

安装包用pip的格式为:

1
pip <命令> [包名]

常用的命令有:

  • install,安装指定的Python包
  • uninstall,卸载指定的Python包
  • list,显示已经安装的Python包

正则表达式模块

具体参考:Python 正则表达式 | 菜鸟教程 (runoob.com)

正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。

Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。

re 模块使 Python 语言拥有全部的正则表达式功能。

compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。

re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。

时间日期模块

datetime模块包含五个用于操控日期和时间的类:

  • date类,日期类。
  • time类,时间类。
  • datatime类,时间和日期类。
  • timedelta类,表示两个datetime对象的差值。
  • tzinfo类,表示时区相关的信息类。

获取时间戳

使用datetime的now()方法可以获得当前的时间。

1
2
3
4
5
from datetime import *

def datetime_test():
time = datetime.now()
print(time)

实现时间日期增减

用timedelta对象,可以方便使用“+”“-”实现时间日期的计算。

1
2
3
4
5
6
7
8
9
def timedelta_test():
'''
实现一天,一小时、一分钟、一秒之后的时间
:return:
'''
time = datetime.now()
after_time = time + timedelta(days=1, hours=1, minutes=1, seconds=1)
print(after_time)

日历模块

Python的日历(calendar)模块,主要实现与日历相关的功能。

返回年历

calendar()函数返回年历指定年的年历,函数原型:

1
calendar ((theyear, w=2, l=1, c=6, m=3))

参数说明:

  • theyear,指定年份。
  • w,日期列宽度。
  • l,每行星期数
  • c,月份列的间隔宽度。
  • m,月份列数。

检测是否为闰年

calendar模块提供的isleep()函数来实现检测给定年份是否是闰年,黑提供了一个leapdays(year1, year2)函数计算在[year1, year2]之间的闰年数量。

返回指定日期是星期几

calendar模块中的weekday(year, month, day)函数,返回指定日期是星期几,0代表星期一。

monthrange(year, month)函数,返回指定年月的第一天是星期几,本月一共有几天。

时间模块

在Python中有三种表达时间的方式;

  • 时间戳,是指某个时间与1970年1月1日00:00的差值,单位为秒。
  • 格式化时间,有字母和数字表示的时间。
  • 时间元组,即(struct_time),共有九个成员
序号 属性
0 tm_year 2008
1 tm_mon 1 到 12
2 tm_mday 1 到 31
3 tm_hour 0 到 23
4 tm_min 0 到 59
5 tm_sec 0 到 61 (60或61 是闰秒)
6 tm_wday 0到6 (0是周一)
7 tm_yday 1 到 366(儒略历)
8 tm_isdst -1, 0, 1, -1是决定是否为夏令时的旗帜

时间戳转化为格式化时间和时间元组

使用time模块中的time()函数,可以获得当前时间的时间戳;然后将时间戳传入ctime()、gmtime()和localtime()函数,可获得格式化时间、gmt时区时间元组和本地时间区时间元组。

时间元组转换为格式化时间和时间戳

给定一个时间元组time_tuple = (2020, 1, 1, 1, 1, 1, 1, 1, 0)使用mktime()函数转化为时间戳,用strftime()函数将其转换为指定格式的时间,使用asctime()转化为格式化时间。

1
2
3
4
def timetuple_to_time():
mytime = (2022, 11, 14, 22, 26, 0, 0, 1, 0) # 定义时间元组
mktime = time.mktime(mytime) # 转化为时间戳
print(time.strftime("%Y年%m月%d日", mytime)) #转换为自定义时间格式 "%Y-%m-%d %H:%M:%S"

格式化时间字符串

通过strptime()函数可以将时间字符串转换为时间元组struct_time形式,但格式参数要与时间字符串一一对应。

1
2
3
4
def timestring_to_struct():
timestring = "2000-12-15 00:00"
strptime = time.strptime(timestring, "%Y-%m-%d %H:%M")
print(strptime)

将线程挂起

time模块提供一个sleep(sec)函数,可以将线程挂起sec秒钟

1
2
3
4
5
def sleeptimes():
before_time = time.time()
time.sleep(12)
after_time = time.time()
print('sleep:{0:.3f}s'.format(after_time-before_time))

Python随机数模块

Python提供一个随机数模块(random),用于生成随机数。

常用的有一下几个函数:

randrange() 返回给定范围之间的随机数。
randint(a,b) 返回给定范围[a,b]之间的随机数。
choice(seq) 返回给定序列seq中的随机元素。
choices() 返回一个列表,其中包含给定序列中的随机选择。
shuffle(x) 接受一个序列x,并以随机顺序返回此序列。
random() 返回 0 与 1 之间的浮点数。
uniform(a,b) 返回两个给定参数[a,b]之间的随机浮点数。

文件与目录操作

基本文件操作

打开文件

Python中创建文件对象用内置的open()函数实现。open()函数会打开一个文件,并返回文件对象。;如果打开文件失败会抛出OSEerror。

open()函数原型:

1
open(file,mode='r', buffering=-1, encoding = None, errors=None, newline=None, closefd=True, opener=None)

参数说明:

  • file,文件路径(必选参数,文件路径使用双下划线)
  • mode,打开文件的方式,默认为’r’,可选参数。
  • buffering,制定缓冲策略,一般保持默认,可选
  • encoding,指定编码方式,默认为None,表示当前操作系统的默认编码方式。
  • error,指定报错级别,默认为None,表示使用严格(strict)模式,可选。
  • newline,指定换行符,默认值为None,表示使用通用换行模式,即在读取时,’\n’,’\r’,or’\r\n’都会当做’\n’但会。在写入时任何’\n’都会当做’\r\n’处理。
  • closefd,指定是否关闭文件描述符,默认值为True,表示传入open()函数的是一个文件名而不是一个文件描述符。
  • opener,传入用户自定的文件打开方法,默认值为None,表示使用Python的默认打开方法。
  • 二进制文件模式,mode参数中附加b,例如rb、wb;
  • 文件文本模式,mode参数中附加t。

不同模式打开文件的完全列表:

模式 描述
t 文本模式 (默认)。
x 写模式,新建一个文件,如果该文件已存在则会报错。
b 二进制模式。
+ 打开一个文件进行更新(可读可写)。
U 通用换行模式(不推荐)。
r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。
r+ 打开一个文件用于读写。文件指针将会放在文件的开头。
rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。
w 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
w+ 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。

文件对象属性

属性 描述
file.closed 返回true如果文件已被关闭,否则返回false。
file.mode 返回被打开文件的访问模式。
file.name 返回文件的名称。
file.softspace 如果用print输出后,必须跟一个空格符,则返回false。否则返回true。

基本文件操作

  • 关闭文件:关闭文件是指把缓冲区内部还没有写入文件的数据写入文件,然后关闭文件。

  • 读取文件:

    方法名称 功能
    read( size = -1) 读取 size 个字符,遇到文件结束符 EOE 后结束读取操作;默认值为1,表示读取全部字符,直到 EOF
    readline( size=-1) 读取 size 个字符,遇到换行符 n或 EOE 后结束读取操作;默认值为-1,表示读取换行符前的全部字符:遇到 EOF 后,返回空字符串
    readlines ( hint = -1) 读取不超过 hint 个字符的行,以列表形式返回,默认值为-1,表示读取 EOF 前的全部行,并以列表形式返回
    tell( ) 返回文件当前位置
    seek ( offset ,whence = 0) 设置文件当前位置;whence=0,从头开始;whence=1,从当前位置开始;whence=2,从尾开始; offset 为正,则向前移动;为负,则向后
  • 写入文件:image-20221115090836390

文件操作最佳实践:with语句

文件的操作一定要成对存在,一面对文件造成不必要的伤害。Python提供了with语句来实现文件的自动关闭操作。

with语句的基本语法为:

1
2
with 表达式[as 对象名]
with语句体

高级文件操作

shutil模块中的常用文件操作

原文参考:(8条消息) Python模块——shutil模块详解_数据分析与统计学之美的博客-CSDN博客_shutil

2020081717024675

类和对象

类是一段可以复用的代码,里面封装了类的属性和方法的详细定义。

类和对象的基本概念和操作

定义类

Python中类的定义通过关键字”class”来实现,一个类包括类名、类的文档字符串、方法定义和属性定义。

语法:

1
2
3
4
class 类名:
执行语句...
零个到多个类变量...
零个到多个方法...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class CLanguage :
# 下面定义了2个类变量
name = "C语言中文网"
add = "http://c.biancheng.net"
def __init__(self,name,add):
#下面定义 2 个实例变量
self.name = name
self.add = add
print(name,"网址为:",add)
# 下面定义了一个say实例方法
def say(self, content):
print(content)
# 将该CLanguage对象赋给clanguage变量
clanguage = CLanguage("C语言中文网","http://c.biancheng.net")

__init__若省略会默认继承父类的__init__方法.

在Python中,类的方法与普通函数有一个明显的区别,在类的方法必须有一个额外的在输入参数列表中排在第一位的参数self,这个参数代表引用对象本身。在调用方法时,Python解释器会自动为self参数赋值。

实例化对象

语法:

1
对象变名 = 类名(参数列表)

初始化对象

在实例化对象的过程中,Python解释器首先调用_new()__方法来创建对象,然后调用__init()_

方法初始化对象。在Python中,对象实例化 = 创建对象 + 初始化对象

创建对象并访问类中的成员

根据访问权限的不同,类的成员可以分为公有类型、私有类型和保护类型。Python中没有严格的语法规定来支持访问权限,但有约定俗成的命名规则:

  • 名字首位加上双下划线,表示这是系统内建类型。
  • 名字开头加双下划线,表示为私有类型。
  • 名字开头加单下划线,表示受保护类型。
  • 名字首位不加下划线,表示这是公有类型。

类的高级操作

继承

继承的语法格式:

1
2
3
4
5
class 类名(基类列表):
‘’‘
类的文档说明
’‘’
语句

方法重写

子类的同名方法会覆盖父类的同名的方法,一般在__init()__中先调用父类的__init()__方法.

测试一个对象是否属于某个类:

isinstance(object,class_or_tuple,/)

参数说明:

  • obj:测试对象
  • class_or_tuple,一个类多个类组成的元组,例如,isinstance(x,(A,B))等于isinstance(s,A) or isinstance(x,B)
  • 返回值,表示该对象属于指定的类,返回True否则返回False

@property装饰器

我们可以使用@property装饰器来创建只读属性,@property装饰器会将方法转换为相同名称的只读属性,可以与所定义的属性配合使用,这样可以防止属性被修改。

1
2
3
4
5
6
7
8
9
class Rect:
def __init__(self,area):
self.__area = area
@property
def area(self):
return self.__area
rect = Rect(30)
#直接通过方法名来访问 area 方法
print("矩形的面积是:",rect.area)

而要想实现修改 area 属性的值,还需要为 area 属性添加 setter 方法,就需要用到 setter 装饰器,它的语法格式如下:

1
2
3
@方法名.setter
def 方法名(self, value):
代码块
1
2
rect.area = 90
print("修改后的面积:",rect.area)