python基础
-
加减乘除
星号*表示乘法,/斜杠表示除法 不能用0做除数 会出现ZeroDivisionError -
整数和浮点数
-
其他数学运算符
幂用表示23=222,商//表示 取余% -
字符串
单引号和双引号
如果要在字符串中展示单引号 或者其他字符 需要加转义字符 换行n 单引号 ’ 制表符 t
使用三引号与换行(""" 需要显示的内容 “”")
例如""“first
second”""
效果等同’firstnsecond’ -
简单的输出和输入
输入默认是字符串 如果你需要数字那么就要使用强转
1
2
3
4
5
6# 定义一个变量m来接受来自控制台的信息 m = input("输入你想输入的内容:") print("输出你输入的内容:" + m) n = int(input("输入你想输入的内容:")) print("输出你输入的内容:" + n)
- 字符串的操作
不管是否为单双引号 字符串之间都可以用+号进行连接
即使字符串包含数字但是仍会像字符串操作一样 将他们连接起来
数字添加字符串则会出现错误 (主要原因是ascII表 )
1
2
3
4
5
6
7
8
9# code print("2"+"5") #两个包含数字的字符串连接 print("2"+1) # 一个包含数字的字符串和数字进行连接 # output 25 "TypeError: can only concatenate str (not "int") to str" # 类型错误 只能连接str(不是“int”)到str
字符串也可以用整数相乘 这会让字符串重复
例如 乘以n 就是让字符重复n次
1
2
3
4
5
6
7
8print("happy" * 3) # happyhappyhappy # 常见的错误 print('happy' * '2') # can't multiply sequence by non-int of type 'str' print('python' * 7.0) # can't multiply sequence by non-int of type 'float'
- 类型转换
1
2
3
4
5print("4" + "5") # 字符的相加 (连接) print(int("4") + int("5")) # 把字符类型强转为int类型
- 变量
变量的命名 1.区分大小写2.不能从数字开始,中间不能有空格3.唯一字符数字,字母,下划线。
可以使用del对变量已经赋过值进行清除
1
2
3
4
5
6
7
8c = 'python' del c # print(c) # NameError: name 'c' is not defined 变量c的值没有定义 c = 'python3.0' print(c) # python3.0
-
快速运算符
+= *= -= /= 数字和字符都可以实现
但是没有专门的操作符 如++ 等 -
单行注释和多行注释
1
2
3
4# 单行注释 " 多行注释" '多行注释'
控制结构
- 布尔值与表达式
python另外的一种类型是Booleans(布尔值)只有两个布尔值Ture 和False
判断式 == 等于 ,!=不等于,>大于,<小于,<=小于 等于,>=大于等于
(注意相同数值的小数和整型 整型大于小数) - if语句
(注意 缩进 python没有缩进是无法工作的)
if 表达式 :
语句
1
2
3
4
5
6
7
8m = 20 if m == 20: # 赋值和等于要分清 冒号代表缩进开始 print(m) else: print(m + 1) # 缩进一致(语句)
if嵌套
1
2
3
4
5
6
7m = 20 if m == 20: print("m不等于20") if m == 10: print("m不等于10") # 缩进一致(语句) 没有缩进代表并列if语句
- else语句
else if简写elif
1
2
3
4
5
6
7
8m = 20 if m == 20: print("m等于20") elif m == 10: print("等于10") elif m == 5: print("等于5")
- 布尔运算
布尔运算符 : and ,or,and or not (和,或者,不是,反 !)
and两边接受两个布尔表达式 这两个布尔表达式 都为真输出 True
or 两个中有一个为真 为True
如果第一个为真 后面的不做判断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19print(4 == 4 and 6 == 6) print(1 == 2 and 2 == 2) print(8 == 8 and 45 == 35) print(1 == 3 or 2 == 5) print(1 == 1 or 2 == 5) print(1 == 1 or 2 == 2) print(1 == 1 or 2 == 2) print(1 == 1 or not 2 == 2) print(not 1 == 1 or 2 == 2) # True # False # False # False # True # True # True # True # Ture
- 运算法符优先级
括号>幂>正负号>乘除>加减>比较运算符>逻辑运算符 - while运算符
false 跳出循环
条件总是为真 true 一直循环 Ctrl+c终止程序
使用break语句 跳出循环 continue 返回循环顶部
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17while m <= 10: print(m + 1) m = m + 1 print("完成") # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 11 # 完成 在这里插入代码片
- list运算符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16data = ["hello", "world", "!"] # data 是一个list列表 # 列表中的某个项目可以通过方括号([])中的索引进行访问 。 print(data[0]) print(data[1]) print(data[2]) # []创建空列表 支持嵌套 溢出 things = ["strings", 0, [2, 3, 'numbers'], 5.60] print(things) # hello # world # ! # ['strings', 0, [2, 3, 'numbers'], 5.6]
- 列表函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18print(data + [5, 5.6]) print(data * 5) # 在这里里可以把list看做字符串 # 这里是对字符串的基本操作 # 字符串被看做不可更改的字符列表 print(2 in data) print(4 not in data) # in运算符用于确定字符 是否是另外一个字符 # 还可以用作字符串是否是另外一个字符串的子字符串 # 运算符not 可以检测某个元素不在列表里 # 输出如下 # [2, 3, 4, 5, 5.6] # [2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4] # True # False # False 在这里插入代码片
- list函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14data = [1, 2, 3] data.append(4) print(data) # [1, 2, 3, 4] 用于在列表最后添加元素 print(len(data)) # len函数用于查看列表中的元素 print(data.index(3)) # 查找某个值的索引 (位置) # output # [1, 2, 3, 4] # 4 # 2
- range
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# range 函数创建有序数字列表生成 # 一个range(10)生成0-9的整数列表 不包含10 单个参数 data = list(range(10)) print(data) # 输出 # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # range(4,9)生成4-9的整数列表,不包含9 两个参数 data = list(range(4, 10)) print(data) # 输出 # [4, 5, 6, 7, 8, 9] # range(3,18,3)生成3-18间隔为3的整数列表 三个参数 data = list(range(3, 18, 3)) print(data) # 输出 # [3, 6, 9, 12, 15]
循环
1.while
2. for -1类似于foreach循环
3… for-2 控制循环次数 用range(n)循环次数n次
1
2
3
4
5
6
7
8
9
10
11
12
13
14data = [1, 2, 3, 4] for i in data: print(i) for i in range(3): print(123456) # 输出 # 1 # 2 # 3 # 4 # 123456 # 123456 # 123456
函数与模块
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# 代码复习 # def -自定义函数 def my_function(): print("str") print("hello world") my_function() # function函数 # 调用函数之前就必须对它进行定义 否则就会出现以下情况 fun() def fun(): print("error") # NameError: name: 'fun' is not defined # fun()函数没有定义 # 函数参数 def print_data(data): print(data + "!") print_data('data') print_data("data") # output # data! # data! # 你可以定义多个参数 用逗号隔开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22# 函数返回值 def min(x, y): if x <= y: return x else: return y print(min(4, 9)) z = min(5, 6) print(z) # output # 4 # 5 # 函数返回值 # 函数一旦返回一个值 它就立即停止运行 返回语句后任何 代码都不执行 def return_w(x): y = x return y print("这个语句将不会打印") print(return_w(10)) # output # 10
1
2
3
4
5
6
7
8
9
10
11
12
13# 函数对象 # function —函数重新赋值 将函数赋给一个变量, 这样变量就可以调用函数了 # 操作与基本函数输出一样 def open_w(x): return x m = 7 op = open_w # 注意这里是函数名称 不是调用函数 print(op(m)) # 参数记得带上
1
2
3
4
5
6
7
8
9
10
11
12
13
14# 函数也可以作为其他函数的参数 def add(x, y): return x + y def do_add(func, x, y): return func(func(x, y), func(x, y)) a = 45 b = 30 print(do_add((add, a, b))) # func = add 对应参数输入 do_add 两次将函数add作为参数 # 并且调用它的主体 # TypeError: do_add() missing 2 required positional arguments: 'x' and 'y'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18# 模块 # random 用来生成随机数 使用基本方法 在文件顶部导入模块名(import module_name) # 然后使用(module——name.变量名) 访问模块中具有名称的函数和值 import random import math from math import pi # 如果你只需要模块的某个功能 可以另外一种导入 使用(from 模块名 import 变量名) 然后使用变量名 for i in range(5): value = random.randint(1, 8) print(value) num = 3 print(math.sqrt(num)) # 还有math库 sqrt用来求根 根默认是小数 1.当根为整数显示小数后一位0 2.默认显示小数后16位 print(pi) # pi是数学里面π的值 默认小数点后15位 # modules 错误 导入一个不可以的模块会导致错误
1
2
3
4
5
6# 尝试导入一个不可用的模块会导致错误 import some_module print("Result") # ModuleNotFoundError: No module named 'some_module' # 模块没有找到错误 :没有名叫some_module名字的模块
1
2
3
4
5
6# 可以使用as关键字在不同的名称下导入模块和对象, # 这主要是在模块和对象具有冗长或混淆的名称时使用 from math import sqrt as sq print(sq(100)) # 10.0
- 库
python 有三种库 外源的 预装的 标准库
标准库有的是python写的 有的是拿C语言写的 多数在所以平台上都能使用
但是有些是在win或Unix专用的
通过pip(命令行)你可以安装GUI的库
文件与异常
1
2
3
4
5
6
7# 异常 常见例子 importerror 导入失败 indexerror 溢出(访问未知空间) nameerror 使用未知变量 sytraceerror 无法正确解析代码 # typeerror 在不适当的类型上调用函数 valueerror 函数调用在正确的类型上,但是具有不适当的值 num1 = 7 num2 = 0 print(num1 / num2) # ZeroDivisionError: division by zero
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
30
31# 异常处理 可以使用try/except 语句对异常代码进行处理 try: num1 = 7 num2 = 0 print(num1 / num2) print("计算完毕") except ZeroDivisionError: print("发生了一个错误") print("一个除以0的操作") # 发生了一个错误 # 一个除以0的操作 # try语句可以有多个块 用来处理不同的异常 try: value = 10 print(value + "hello") print(value / 5) except ZeroDivisionError: print("divided by zero") except (ValueError, TypeError): print("error occurred") # error occurred # 指定的except语句将捕捉所以的错误 try: sid = "spam" print(sid / 0) except: print("发生了一个错误") # 发生了一个错误
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
30# finally 语句 为了确保某些代码正常运行 不管发生什么错误 都可以使用最终语句 # 一般把 finally语句放在try/except 语句之后 try/except 中执行也可以 try: print("hello") print(1 / 0) except ZeroDivisionError: print("0不能做分母") finally: print("这条代码是必须的") # hello # 0不能做分母 # 这条代码是必须的 try: print(2) print(1 / 0) except ZeroDivisionError: print(var) finally: print("这条代码是必须的") # ZeroDivisionError: division by zero # During handling of the above exception, another exception occurred: # NameError: name 'var' is not # 异常抛出 print(1) raise ValueError print(2) # ValueError # 处理一个错误的时候,另外一个错误发生, # 名称错误:没有var没有定义过
1
2
3
4
5
6# 异常抛出 print(1) raise ValueError print(2) # ValueError
1
2
3
4
5name = "245" raise NameError(" invalid name!") # NameError: invalid name!
1
2
3
4
5
6
7
8
9# 在try/except块中,可以使用不带参数的raise语句来引发任何异常 try: num = 5 / 0 except: print("一个错误发生") raise # 一个错误发生 # ZeroDivisionError: division by zero
1
2
3
4
5
6
7
8
9
10
11
12# Assertions断点 断点是一种明智的检查,当您完成程序测试时,您可以打开或关闭 # 断点测试表达式,如果结果为false,则引发异常 print(1) assert 2 + 2 == 4 print(2) assert 1 + 1 == 3 print(3) # AssertionError # assert 1 + 1 == 3 # 1 # 2
1
2
3
4
5
6
7# 断点可以采用第二个参数 如果断点失败 则传递给断点错误 跟try/except 差不多 # 但是如果不处理 这种类型的异常会终止程序 tem = -10 assert (tem > 0), "小于0" # assert (tem > 0), "小于0" # AssertionError: 小于0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21# 文件用完一定要关闭 # 打开文件 使用open函数打开文件 文本文件最容易 前提是同级目录有名叫 # file.txt的文件 并且里面有 line1 n line2 n line3 n # open("file.txt", 'r') 这里的r代表读取 也可以省略 w代表写入文件 # 用len函数可以求文件大小 # 若要检索文件的每一行 可以使用readlines方法返回一个列表 my_file = open("file.txt", ) print(my_file.readline()) contact = my_file.read() print(contact) print(len(contact)) # 长度为0 my_file.close() # line1 # line2 # line3 # 11
1
2
3
4
5
6
7
8
9# 您还可以使用for循环来迭代文件中的行 file = open("file.txt", 'r') for line in file: print(line) file.close() # line1 # line2 # line3
1
2
3
4
5
6
7
8
9
10# 写入文件 需要使用write方法 ,此方法是将字符串写入文件 w模式如果没有文件 # 它会创建一个 当文件以写模式打开时 文件已有的内容会被删除 file = open("file.txt", 'w') file.write("写入字符串在文件里") file.close() file = open("file.txt", 'r') print(file.read()) file.close() # 写入字符串在文件里
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20file = open("file.txt", 'r') print("初始化读写内容") print(file.read()) print("完成") file.close() file = open("file.txt", 'w') file.write("新的内容") file.close() file = open("file.txt", 'r') print("写入新的内容") print(file.read()) print("结束") file.close() # 初始化读写内容 # 写入字符串在文件里 # 完成 # 写入新的内容 # 新的内容 # 结束
1
2
3
4
5
6
7
8
9# 用write 方法返回写入文件的字节数 words = "hello world" file = open("file.txt", 'w') count_words = file.write(words) print(count_words) file.close() # 字节数11
1
2
3
4
5
6
7
8
9
10
11
12
13# 使用文件 # 关闭文件 用try/finally 更好确保文件关闭 即使发生错误 try: file = open("file.txt") print(file.read()) finally: file.close() # hello world # 处理文件 还有第二种方法 with 语句 with open("file.txt") as f: print(f.read()) # hello world
更多类型
1
2
3
4
5
6
7
8
9# none 空 是一个类型 也是一个对象不等于 空的字符串 不等于空的列表 不等于0 不等于False # lambda 函数不像 命名函数那么强大 只能做单个表达式 等同于一行代码 def poll(x): # 命名函数 return x ** 2 + 5 * x + 4 print(poll(-4)) # 0
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164print((lambda x: x ** 2 + 5 * x + 4)(-4)) # x=-4 # 0 # 字典 字典用于将任意键映射到值的数据结构 # 字典可以用于与列表相同的方式索引 ,使用包含键的方括号 ages = {"Dave": 24, "Mary": 42, "John": 58} print(ages["Dave"]) print(ages["Mary"]) # 24 # 42 # 字典中的每个元素都由键: 值对表示 # 试图索引不是词典的一部分的键 返回值错误 # print(ages["MM"]) # KeyError: 'MM' 键错误 # 对象不可变(还有列表) # tuple元组 # 元组和列表非常相似,除了他们是不可变的(它们不能被改变) # 用括号创建 不是方括号 用逗号分隔 eggs = ("span", "eggs", "message") print(eggs[0]) # span # 试图重新赋值元组的值会导致错误,即不支持赋值 # eggs[0] = "mm" # TypeError: 'tuple' object does not support item assignment # 列表切片 列表名字[开始位置:结束位置] mm = [0, 1, 2, 3, 4, 5, 6, 6, 5, 5, 56, 6, 56, 6] print(mm[2:10]) # [2, 3, 4, 5, 6, 6, 5, 5] # 如果忽略第一个数 默认从开头开始 忽略第二个数字 会默认输出到结尾 print(mm[:10]) print(mm[7:]) # [0, 1, 2, 3, 4, 5, 6, 6, 5, 5] # [6, 5, 5, 56, 6, 56, 6] # 列表切片还有第三个数字 表示步进 不包含最后一个 # 数字为负 表示从尾部开始计数 # 列表推导式 app = [i ** 3 for i in range(5)] # 循环5次 print(app) # [0, 1, 8, 27, 64] # 嵌套if语句 来强制列表中的值的条件。 en = [i ** 2 for i in range(5) if i ** 2 % 2 == 0] print(en) # [0, 4, 16] # 试图在一个非常广泛的范围内创建列表会导致内存错误 # ene = [2 * 3 for i in range(10 ** 100)] # MemoryError # 字符串格式化 # 将非字符串转化为字符 nums = [4, 5, 9] msg = "numbers:{0} {1} {2}".format(nums[0], nums[1], nums[2]) print(msg) # numbers:4 5 9 # 把每个参数放在对应未知的字符串中这是使用{}确定的 a = "{x}, {y}".format(x=5, y=7) print(a) # 5, 7 # 有用的函数 # 字符串函数 print(",".join(["spam", "edd"])) # spam,edd 列表转字符串 带有某个分隔符 print("hello me".replace("me", "world")) # hello world 替换对应的字符 print("this is.".startswith("this")) # True 开头是否有 某字符串 print("this is.".endswith("is.")) # True 结尾是否有某字符串 print("this is.".upper()) # THIS IS. 全部大写 print("this is.".lower()) # this is.全部小写 print("this, is".split(",")) # ['this', ' is'] 字符串转列表 带有某个分隔符 # 数值函数 print(min(1, 3, 2, 4, 65, 5, 6, 5, 5, 6)) # 1 print(max(1, 2, 3, 585, 6, 4, 56, 4, 6)) # 585 print(abs(-997)) # 绝对值 # 997 print(sum([1, 2, 6, 56, 43, 34])) # 142 # 列表函数 numd = [22, 55, 44, 77, 88] if all([i > 5 for i in numd]): print("所有比5大的") # 所有比5大的 if any([i % 2 == 0 for i in numd]): print("输出偶数") # 输出偶数 for m in enumerate(numd): print(m) # (0, 22) # (1, 55) # (2, 44) # (3, 77) # (4, 88) # 文本分析器 def count_char(text, char): count = 0 for c in text: if c == char: count += 1 return count filename = input("请输入文件名:") with open(filename) as f: text = f.read() print(count_char(text, "r")) f.close() # 结果是 1 # 查询r在文件中出现的次数 def count_char(text, char): count = 0 for c in text: if c == char: count += 1 return count filename = input("请输入文件名:") with open(filename) as f: text = f.read() print(count_char(text, "r")) for char in "abcdefghijklmnopqrstuvwxyz": perc = 100 * count_char(text, char) / len(text) print("{0} - {1}%".format(char, round(perc, 2))) f.close() # 查找字母表中每个字符所占的百分比 # 1 # a - 0.0% # b - 0.0% # c - 0.0% # d - 9.09% # e - 9.09% # f - 0.0% # g - 0.0% # h - 9.09% # i - 0.0% # j - 0.0% # k - 0.0% # l - 27.27% # m - 0.0% # n - 0.0% # o - 18.18% # p - 0.0% # q - 0.0% # r - 9.09% # s - 0.0% # t - 0.0% # u - 0.0% # v - 0.0% # w - 9.09% # x - 0.0% # y - 0.0% # z - 0.0%
函数程序设计
- 函数式编程
函数式编程是一种编程风格,(顾名思义)是基于函数的。
函数编程的一个关键部分是高阶函数。在上一节关于函数作为对象的课程中,我们已经简要地看到了这个想法。高阶函数将其他函数作为参数,或将它们作为结果返回。
例如:
def apply_twice(func, arg):
return func(func(arg))
def add_five(x):
return x + 5
print(apply_twice(add_five, 10))
函数apply_twice使用另一个函数作为它的参数,并在它的主体内部调用它两次。
函数
函数式编程试图使用纯函数。纯函数没有副作用,只返回依赖于它们的参数的值。
这就是函数在数学中的作用:例如,对于相同的x值,cos(x) 总是返回相同的结果。
下面是纯函数和不纯函数的例子。
1
2
3
4
5
6
7def pure_function(x, y): temp = x + 2*y return temp / (2*x + y) some_list = [] def impure(arg): some_list.append(arg)
上面的函数不是纯的,因为它改变了某个列表的状态
lambdas
lambda函数不像命名函数那么强大。
它们只能做需要单个表达式的事情,通常等同于一行代码。
例如:
1
2
3
4
5
6
7
8
9#命名函数 def polynomial(x): return x**2 + 5*x + 4 print(polynomial(-4)) #lambda print((lambda x: x**2 + 5*x + 4) (-4)) </b></b> >>>结果: 0
在上面的代码中,我们创建了一个匿名函数,并用一个参数调用它。
-4×-4+5×-4+4=0
Lambdas
lambda函数可以被分配给变量,并且使用类似于正常函数。
1
2
3
4
5
6
7double = lambda x: x * 2 print(double(7)) 结果: >>> 14 >>>
然而,很少有一个很好的理由这样做——通常用DEF来定义函数是更好的。
map与filter
内置函数映射map和过滤器filter是非常有用的在列表上操作的高阶函数(或类似的对象称为迭代器)。
函数映射map采用一个函数和一个迭代作为参数,并返回一个新的迭代函数,应用于每个参数。
例如:
1
2
3
4
5
6
7
8
9
10def add_five(x): return x + 5 nums = [11, 22, 33, 44, 55] result = list(map(add_five, nums)) print(result) 结果: >>> [16, 27, 38, 49, 60] >>>
我们可以通过使用lambda语法更容易地达到相同的结果。
1
2
3
4nums = [11, 22, 33, 44, 55] result = list(map(lambda x: x+5, nums)) print(result)
要将结果转换为列表,我们使用列表显式
Generators
生成器Generatorsd是一种可迭代的类型,像列表或元组。 与列表不同,它们不允许用任意索引进行索引,但它们仍然可以通过for循环迭代。
它们可以使用函数和yield语句来创建。
例如:
1
2
3
4
5
6
7
8def countdown(): i=5 while i > 0: yield i i -= 1 for i in countdown(): print(i)
结果:
5
4
3
2
1
yield语句用于定义一个生成器,替换函数的返回,从而在不破坏局部变量的情况下向调用方提供结果。
Generators
通过将它们作为参数传递给列表函数,可以将有限生成器转换为列表。
1
2
3
4
5
6def numbers(x): for i in range(x): if i % 2 == 0: yield i print(list(numbers(11)))
结果:
[0, 2, 4, 6, 8, 10]
使用生成器会提高性能,这是懒惰(按需)生成值的结果,这意味着内存使用率较低。此外,我们不需要等到所有元素生成之前,才开始使用它们
由于它们一次产生一个项,所以生成器没有列表的内存限制。
事实上,它们可以是无限的!
1
2
3
4
5
6def infinite_sevens(): while True: yield 7 for i in infinite_sevens(): print(i)
结果:
7
7
7
7
7
7
7
…
简而言之,生成器允许你声明一个像迭代器一样的函数,也就是说它可以在for循环中使用。
与map一样,如果要打印结果,则必须将其显式转换为列表。
filter
函数过滤器filter通过删除与条件不匹配的项(返回布尔值的函数)来过滤一个可迭代的
1
2
3
4nums = [11, 22, 33, 44, 55] res = list(filter(lambda x: x%2==0, nums)) print(res)
结果:
[22, 44]
通过将它们作为参数传递给列表函数,可以将有限生成器转换为列表。
1
2
3
4
5
6def numbers(x): for i in range(x): if i % 2 == 0: yield i print(list(numbers(11)))
结果:
[0, 2, 4, 6, 8, 10]
使用生成器会提高性能,这是懒惰(按需)生成值的结果,这意味着内存使用率较低。此外,我们不需要等到所有元素生成之前,才开始使用它们。
装饰器Decorators
装饰器提供了一种使用其他函数修改函数的方法。
当您需要扩展不想修改的函数的功能时,这是理想的。
例如:
1
2
3
4
5
6
7
8
9
10
11def decor(func): def wrap(): print("============") func() print("============") return wrap def print_text(): print("Hello world!") decorated = decor(print_text) decorated()
1
2
3
4
5结果: ============ Hello world! ============
Decorators
在前面的示例中,我们通过将包含函数的变量替换为包装版本来美化函数。
1
2
3
4
5
6
7
8
9
10def decor(func): def wrap(): print("============") func() print("============") return wrap def print_text(): print("Hello world!") print_text = decor(print_text)
这种模式可以在任何时候使用,包装任何功能。 Python通过在装饰函数名称和@符号之前挂起函数定义来支持在装饰器中包装一个函数。 如果我们定义一个函数,我们可以用@符号“装饰”它:
1
2
3
4@decor def print_text(): print("Hello world!")
这将具有与上述代码相同的结果。
单个函数可以有多个装饰器。
递归
递归函数
递归函数可以是无限的,就像无限的循环一样。当忘记实现基本情况时,通常会发生这些情况。
下面是阶乘函数的错误版本。它没有基本情况,所以它运行直到解释器内存不足并崩溃。
def factorial(x):
return x * factorial(x-1)
print(factorial(5))
结果:
RuntimeError: maximum recursion depth exceeded
递归函数
递归也可以是间接的。一个函数可以调用第二个函数,它调用第一个调用第二个函数的函数,以此类推。这可以发生在任意数量的函数中。
例如:
1
2
3
4
5
6
7
8
9
10def is_even(x): if x == 0: return True else: return is_odd(x-1) def is_odd(x): return not is_even(x) print(is_odd(17)) print(is_even(23))
结果:
True
False
Sets
集合以不同的方式与列表不同,但共享多个列表操作,例如len。
它们是无序的,这意味着它们不能被索引。
它们不能包含重复元素。
由于它们被存储的方式,检查一个项目是否是一个集合的一部分,而不是一个列表的一部分是比较快的。
不要使用append来添加到一个集合中,而是使用add。
方法移除从集合中移除特定元素;pop移除任意元素。
1
2
3
4
5
6nums = {1, 2, 1, 3, 1, 4, 5, 6} print(nums) nums.add(-7) nums.remove(3) print(nums)
结果:
{1, 2, 3, 4, 5, 6}
{1, 2, 4, 5, 6, -7}
集合的基本用途包括成员资格测试和消除重复条目。
集合
集合可以使用数学运算组合。
联合运算符 | 将两个集合组合成一个包含两个项的新集合。
交集操作符 &只在两者中获取项。
差分运算符 - 在第一个集合中获取项目,而不是在第二个集合中获取项目。
对称差分算子^在两个集合中得到项目,但不是两者。
1
2
3
4
5
6
7
8first = {1, 2, 3, 4, 5, 6} second = {4, 5, 6, 7, 8, 9} print(first | second) print(first & second) print(first - second) print(second - first) print(first ^ second)
结果:
{1, 2, 3, 4, 5, 6, 7, 8, 9}
{4, 5, 6}
{1, 2, 3}
{8, 9, 7}
{1, 2, 3, 7, 8, 9}
数据结构
如我们在前面的课程中看到的,Python支持以下数据结构:列表、字典、元组、集合。
迭代器
itertools 迭代工具
在迭代工具上运行的迭代函数有很多类似于映射和过滤的函数。
一些例子: takewhile(pred, seq) -当pred对seq[n]的调用返回True时才开始迭代。 chain - 链-把几个迭代函数组合成一个长的迭代; accumulate -累加-返回一个迭代的值。
1
2
3
4
5from itertools import accumulate, takewhile nums = list(accumulate(range(8))) print(nums) print(list(takewhile(lambda x: x<= 6, nums)))
结果
[0, 1, 3, 6, 10, 15, 21, 28]
[0, 1, 3, 6]
解释
[0, 1, 3, 6, 10, 15, 21, 28]
0+0=0
1+0=1
2+1=3
3+3=6
4+6=10
5+10=15
6+15=21
7+21=28
何时使用其他类型:
如果您有不需要随机访问的数据集合,请使用列表。在需要频繁修改的简单迭代集合时,尝试选择列表。
-如果需要元素的唯一性,则使用集合。
在数据不能更改时使用元组。
很多时候,元组与字典结合使用,例如,元组可能表示一个键,因为它是不可变的。
何时使用词典:
-当您需要键/值对之间的逻辑关联时。
-当需要根据自定义键快速查找数据时。
-当您的数据不断修改时。记住,词典是可变的。
面向对象
- 类
我们以前已经看了两种编程范式——命令(使用语句、循环和函数作为子例程)和函数(使用纯函数、高阶函数和递归)。
另一个非常流行的范例是面向对象编程(OOP)。
对象是使用类创建的,这些类实际上是OOP的焦点。 类描述对象将是什么,但与对象本身分离。换句话说,一个类可以被描述为对象的蓝图、描述或定义。 可以使用与创建多个不同对象的蓝图相同的类。
类是使用关键字类和缩进块创建的,其中包含类方法(它们是函数)。
下面是一个简单类及其对象的例子。
1
2
3
4
5
6
7
8class Cat: def __init__(self, color, legs): self.color = color self.legs = legs felix = Cat("蛋黄", 4) rover = Cat("绿色", 4) stumpy = Cat("棕色", 3)
这个代码定义了一个名为CAT的类,它有两个属性:颜色和腿。
然后,该类用于创建该类的3个独立对象。
init
一个类中的最重要的方法是__init__方法。 当使用类名称作为函数时,创建类的实例(对象)时调用。 所有方法都必须有自己作为第一个参数,尽管它没有显式传递,Python为您添加了自变量到列表中;在调用方法时不需要包含自变量。在方法定义中,“自我”指的是调用该方法的实例。 类的实例具有属性,这些属性是与它们相关联的数据片段。 在这个例子中,CAT实例具有颜色和腿的属性。这些可以通过放置一个点和一个实例之后的属性名来访问。 因此,在__init__方法中, self.attribute 设置实例属性的初始值。
例如:
1
2
3
4
5
6
7class Cat: def __init__(self, color, legs): self.color = color self.legs = legs felix = Cat("ginger", 4) print(felix.color)
结果:
ginger
在上面的示例中,__init__方法采用两个参数,并将它们赋给对象的属性。方法是类构造函数。
类 class
练习
类 class
我们以前已经看了两种编程范式——命令(使用语句、循环和函数作为子例程)和函数(使用纯函数、高阶函数和递归)。
另一个非常流行的范例是面向对象编程(OOP)。
对象是使用类创建的,这些类实际上是OOP的焦点。 类描述对象将是什么,但与对象本身分离。换句话说,一个类可以被描述为对象的蓝图、描述或定义。 可以使用与创建多个不同对象的蓝图相同的类。
类是使用关键字类和缩进块创建的,其中包含类方法(它们是函数)。
下面是一个简单类及其对象的例子。
1
2
3
4
5
6
7
8class Cat: def __init__(self, color, legs): self.color = color self.legs = legs felix = Cat("蛋黄", 4) rover = Cat("绿色", 4) stumpy = Cat("棕色", 3)
这个代码定义了一个名为CAT的类,它有两个属性:颜色和腿。
然后,该类用于创建该类的3个独立对象。
21 19375
单选 什么类型的对象是一种方法?
AInteger
BFunction
CClass
init
一个类中的最重要的方法是__init__方法。 当使用类名称作为函数时,创建类的实例(对象)时调用。 所有方法都必须有自己作为第一个参数,尽管它没有显式传递,Python为您添加了自变量到列表中;在调用方法时不需要包含自变量。在方法定义中,“自我”指的是调用该方法的实例。 类的实例具有属性,这些属性是与它们相关联的数据片段。 在这个例子中,CAT实例具有颜色和腿的属性。这些可以通过放置一个点和一个实例之后的属性名来访问。 因此,在__init__方法中, self.attribute 设置实例属性的初始值。
例如:
1
2
3
4
5
6
7class Cat: def __init__(self, color, legs): self.color = color self.legs = legs felix = Cat("ginger", 4) print(felix.color)
结果:
ginger
在上面的示例中,__init__方法采用两个参数,并将它们赋给对象的属性。方法是类构造函数。
11 18919
填空 填空创建一个类及其构造函数,取一个参数并将
1
2
3
4
5
6Student def (self, name): self = name test = Student("Bob")
Methods 方法
类可以定义其他方法来向它们添加功能。
记住,所有的方法都必须有自我作为它们的第一个参数。
这些方法使用与属性相同的点语法访问。
例如:
1
2
3
4
5
6
7
8
9
10class Dog: def __init__(self, name, color): self.name = name self.color = color def bark(self): print("Woof!") fido = Dog("Fido", "brown") print(fido.name) fido.bark()
结果:
Fido
Woof!
类还可以具有类属性,通过在类的主体中赋值变量来创建类属性。这些可以从类的实例访问,也可以从类本身访问。
例如:
1
2
3
4
5
6
7
8
9class Dog: legs = 4 def __init__(self, name, color): self.name = name self.color = color fido = Dog("Fido", "brown") print(fido.legs) print(Dog.legs)
结果:
4
4
类属性由类的所有实例共享。
试图访问未定义的实例的属性会导致AttributeError.(属性错误)。这也适用于调用一个未定义的方法。
例如:
1
2
3
4
5
6
7class Rectangle: def __init__(self, width, height): self.width = width self.height = height rect = Rectangle(7, 8) print(rect.color)
结果:
AttributeError: ‘Rectangle’ object has no attribute ‘color’
Methods类方法
到目前为止,我们查看的对象的方法由类的实例调用,然后传递给方法的自参数。 类方法是不同的——它们由类调用,该类传递给方法的CLS参数。 这些方法的一个常见用途是工厂方法,它使用与通常传递给类构造函数的参数不同的参数实例化类的实例。 类方法用类方法装饰器标记。
例如:
1
2
3
4
5
6
7
8
9
10
11
12class Rectangle: def __init__(self, width, height): self.width = width self.height = height def calculate_area(self): return self.width * self.height @classmethod def new_square(cls, side_length): return cls(side_length, side_length) square = Rectangle.new_square(5) print(square.calculate_area())
结果:
25
new_square 是类方法 在类上调用,而不是在类的实例上调用。 它返回cls类的新
从技术上讲,参数自身和cls只是约定,它们可以被更改为其他任何东西。然而,它们是普遍遵循的,所以坚持使用它们是明智的。
2. 继承
继承提供了一种在类之间共享功能的方法。
想象几个类(class),猫,狗,兔子等等。虽然它们在某些方面可能不同(只有狗可能有方法叫喊),但它们很可能在其他方面是相似的(所有都具有颜色和名称的属性)。
这种相似性可以通过使它们都从包含共享功能的超类动物继承来表达。
若要从另一个类继承类,请在类名后面插入括号中的超类名称。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<b><b> class Animal: def __init__(self, name, color): self.name = name self.color = color class Cat(Animal): def purr(self): print("咕噜咕噜...") class Dog(Animal): def bark(self): print("旺旺旺!") fido = Dog("Fido", "棕色") print(fido.color) fido.bark() </b></b> 结果: <b><b><b><b> >>> 棕色 旺旺旺! >>> </b></b></b></b>
从另一个类继承的类称为子类。 继承的类称为超类。
如果一个类继承了另一个具有相同属性或方法的类,则重写它们。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class Wolf: def __init__(self, name, color): self.name = name self.color = color def bark(self): print("喔...") class Dog(Wolf): def bark(self): print("旺旺旺!") husky = Dog("Max", "grey") husky.bark() 结果: >>> 旺旺旺! >>>
在上面的例子中,Wolf是超类,Dog是子类。
继承也可以是间接的。一个类可以从另一个类继承,并且该类可以从第三个类继承。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20class A: def method(self): print("A method") class B(A): def another_method(self): print("B method") class C(B): def third_method(self): print("C method") c = C() c.method() c.another_method() c.third_method() 结果: >>> A method B method C method >>>
然而,循环继承是不可能的。
函数Super是一个有用的继承相关函数,它引用父类。它可以用来在对象的超类中找到具有特定名称的方法。
例如:
1
2
3
4
5
6
7
8
9class A: def spam(self): print(1) class B(A): def spam(self): print(2) super().spam() B().spam()
结果:
2
1
super().spam() 调用A的spam方法.
- 魔术方法
魔术方法是一种特殊的方法,在名字的开头和结尾有两个下划线。
他们也被称为 dunders。
到目前为止,我们所遇到的唯一一个是第二个,但还有几个。 它们用于创建不能被表示为正常方法的功能。 其中一个常见的用法是运算符重载。 这意味着为自定义类定义运算符,这些操作符允许操作符如+和*用于它们。
一个示例性的魔术方法__add__ :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class Vector2D: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): return Vector2D(self.x + other.x, self.y + other.y) first = Vector2D(5, 7) second = Vector2D(3, 9) result = first + second print(result.x) print(result.y) 结果: >>> 8 16 >>>
__add__方法允许定义类中的+运算符的自定义行为。
如您所见,它添加对象的相应属性,并返回包含结果的新对象。
一旦它被定义,我们就可以把两个类的对象加在一起。
jnit__方式是类的初始化
更多的魔术方法
sub 用于 -
mul 用于 *
truediv 用于 /
floordiv 用于 //
mod 用于 %
pow 用于 **
and 用于 &
xor 用于 ^
or 用于 |
表达式x+y被翻译成 x.add(y)
但是,如果x没有实现__add,并且x和y是不同类型的,则调用 y.radd(x) 。
刚才提到的所有魔法方法都有等价的R方法。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class SpecialString: def __init__(self, cont): self.cont = cont def __truediv__(self, other): line = "=" * len(other.cont) return " ".join([self.cont, line, other.cont]) spam = SpecialString("spam") hello = SpecialString("Hello world!") print(spam / hello) 结果: >>> spam ============ Hello world! >>>
在上面的例子中,我们定义了我们的类特殊字符串的除法运算。
Python还提供了比较的神奇方法。
lt 为 <
le 为 <=
eq 为 ==
ne 为 !=
gt 为 >
ge 为 >=
如果 __ne__没有继承任何方法,他将指的是 eq 相反的意思
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20class SpecialString: def __init__(self, cont): self.cont = cont def __gt__(self, other): for index in range(len(other.cont)+1): result = other.cont[:index] + ">" + self.cont result += ">" + other.cont[index:] print(result) spam = SpecialString("spam") eggs = SpecialString("eggs") spam > eggs 结果: >>> >spam>eggs e>spam>ggs eg>spam>gs egg>spam>s eggs>spam> >>>
几种其他的魔术方法
len_ 为 len()
getitem 为 i查找
setitem 为元素赋值
delitem 删除元素
iter 为 对象上的迭代(例如in for循环)
contains 为 in
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21import random class VagueList: def __init__(self, cont): self.cont = cont def __getitem__(self, index): return self.cont[index + random.randint(-1, 1)] def __len__(self): return random.randint(0, len(self.cont)*2) vague_list = VagueList(["A", "B", "C", "D", "E"]) print(len(vague_list)) print(len(vague_list)) print(vague_list[2]) print(vague_list[2]) 结果: >>> 6 7 D C >>>
我们已经为类重写了len() 函数来返回一个随机数。
索引函数还根据表达式从列表中的范围返回一个随机项。
4. 生命周期
对象生命周期
对象的生命周期是由它的创建、操作和销毁组成的。 对象生命周期的第一个阶段是它所属的类的定义。 下一阶段是实例的实例化,当调用内存被分配来存储实例。在这种情况发生之前,调用类的α-NexSuy方法。这通常只在特殊情况下被重写。 在这种情况发生后,该对象已准备好使用。
其他代码可以通过调用对象上的函数并访问其属性来与对象交互。 最终,它将被使用,并且可以被销毁
当对象被销毁时,分配给它的内存被释放,并且可以用于其他目的。 当一个对象的引用计数达到零时,就会发生一个对象的破坏。引用计数是指引用对象的变量和其他元素的数目。 如果没有任何东西引用它(它有一个引用计数为零),任何东西都不能与之交互,因此它可以被安全地删除。
在某些情况下,两个(或多个)对象只能相互参照,因此也可以被删除。 DEL语句将对象的引用计数减少一个,这常常导致其删除。 DEL语句的神奇方法是 del。 删除不再需要的对象的过程称为垃圾回收。
总之,当对象被分配了新的名称或被放置在容器(列表、元组或字典)中时,对象的引用计数就会增加。当用del删除对象、重新分配其引用或引用超出范围时,对象的引用计数会减少。当对象的引用计数达到零时,Python会自动删除它。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17a = 42 # 创建对象 <42> b = a # 增加对象指向 <42> c = [a] #f增加对象指向 <42> del a # Decrease ref. count of <42> b = 100 # Decrease ref. count of <42> c[0] = -1 # Decrease ref. count of <42>
像C这样的低级语言没有这种自动内存管理。.
- 封装
面向对象编程的一个关键部分是封装,它涉及将相关变量和函数打包为单个易于使用的对象——类的实例。 一个相关的概念是数据隐藏,它指出类的实现细节应该被隐藏,并且为希望使用类的人提供一个干净的标准接口。 在其他编程语言中,这通常通过私有方法和属性来完成,私有方法和属性阻止对类中的某些方法和属性的外部访问。 Python逻辑略有不同。它经常被描述为“we are all consenting adults here”,意思是你不应该对访问一个类的部分设置任意的限制。因此,没有办法执行严格的私有方法或属性。
然而,有一些方法可以阻止人们访问类的一部分,比如通过封装隐藏实现细节。
弱私有方法和属性在开始时有一个下划线。 这表明它们是私有的,不应该被外部代码使用。然而,它通常只是一个约定,并不能阻止外部代码访问它们。 它的唯一实际效果是,从MeaveNoEnsix*不会导入从一个下划线开始的变量。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class Queue: def __init__(self, contents): self._hiddenlist = list(contents) def push(self, value): self._hiddenlist.insert(0, value) def pop(self): return self._hiddenlist.pop(-1) def __repr__(self): return "Queue({})".format(self._hiddenlist) queue = Queue([1, 2, 3]) print(queue) queue.push(0) print(queue) queue.pop() print(queue) print(queue._hiddenlist)
结果:
Queue([1, 2, 3])
Queue([0, 1, 2, 3])
Queue([0, 1, 2])
[0, 1, 2]
在上面的代码中,属性 hiddenlist被标记为私有的,但是它仍然可以在外部代码中访问。 实例的字符串表示采用了__repr_ 魔术方法。
强私有方法和属性在其名称的开头具有双下划线。这导致它们的名称被损坏,这意味着它们不能从类外部访问。 这样做的目的不是确保它们保持私有,而是避免如果存在具有相同名称的方法或属性的子类,则避免错误。 __privatemethod的方法仍然可以从外部访问,但可以用不同的名称访问。 Spam 类的私有方法可以用_Spam__方法进行外部访问。
1
2
3
4
5
6
7
8
9class Spam: __egg = 7 def print_egg(self): print(self.__egg) s = Spam() s.print_egg() print(s._Spam__egg) print(s.__egg)
结果:
7
7
AttributeError: ‘Spam’ object has no attribute ‘__egg’
基本上,Python通过在内部更改名称以包含类名来保护这些成员。
6. 静态方法
静态方法类似于类方法,只是它们不接收任何附加参数;它们与属于类的常规函数相同。 它们用静态方法装饰器标记。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13class Pizza: def __init__(self, toppings): self.toppings = toppings @staticmethod def validate_topping(topping): if topping == "pineapple": raise ValueError("No pineapples!") else: return True ingredients = ["cheese", "onions", "spam"] if all(Pizza.validate_topping(i) for i in ingredients): pizza = Pizza(ingredients)
静态方法的行为类似于普通函数,除非您可以从类的实例调用它们。
7. 属性
属性提供了一种自定义对实例属性的访问的方法。 它们是通过将属性修饰符放在方法之上创建的,这意味着当访问与该方法同名的实例属性时,将调用该方法。 属性的一个常见用途是使属性只读。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Pizza: def __init__(self, toppings): self.toppings = toppings @property def pineapple_allowed(self): return False pizza = Pizza(["cheese", "tomato"]) print(pizza.pineapple_allowed) pizza.pineapple_allowed = True 结果: >>> False AttributeError: can't set attribute >>>
属性也可以通过定义setter/getter函数来设置。 setter函数设置相应的属性值。 getter获取值。 要定义一个setter,您需要使用与属性相同名称的装饰器,后面跟着一个点和SETER关键字。 这同样适用于定义getter函数。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20class Pizza: def __init__(self, toppings): self.toppings = toppings self._pineapple_allowed = False @property def pineapple_allowed(self): return self._pineapple_allowed @pineapple_allowed.setter def pineapple_allowed(self, value): if value: password = input("Enter the password: ") if password == "Sw0rdf1sh!": self._pineapple_allowed = value else: raise ValueError("Alert! Intruder!") pizza = Pizza(["cheese", "tomato"]) print(pizza.pineapple_allowed) pizza.pineapple_allowed = True print(pizza.pineapple_allowed)
结果:
False
Enter the password: Sw0rdf1sh!
True
正则表达式
- 正则表达式
正则表达式是各种字符串操作的有力工具。 它们是一种特定于域的语言(DSL),它以大多数现代编程语言的形式存在于库中,而不仅仅是Python。
它们对两个主要任务有用:
-验证字符串与模式匹配(例如,字符串具有电子邮件地址的格式),
-用字符串替换(例如将所有土豆改为马铃薯)。
领域特定语言是高度专业化的迷你编程语言。 正则表达式是一个流行的例子,SQL(用于数据库操作)是另一个例子
2.Python中的正则表达式可以使用RE模块来访问,re模块是标准库的一部分。
定义了正则表达式之后,可以使用re.match函数来确定它是否匹配字符串的开头。
如果匹配,则返回一个表示匹配的对象,如果不是,则返回None。 为了避免在使用正则表达式时出现混淆,
我们将使用r“表达式”。 这使得正则表达式更容易使用。
例如:
1
2
3
4
5
6
7import re pattern = r"spam" if re.match(pattern, "spamspamspam"): print("匹配") else: print("不匹配")
结果:
匹配
上面的示例检查模式“spam”是否匹配字符串并打印“匹配”。
这里模式是一个简单的单词,但是存在各种字符,当在正则表达式中使用这些字符时,它们将具有特殊的含义。
3.匹配模式的其他功能是 re.search和re.findall。 函数re.search在字符串中的任意位置找到模式匹配。 函数re.findall 返回与模式匹配的所有子串的列表。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18import re pattern = r"spam" if re.match(pattern, "eggspamsausagespam"): print("Match") else: print("No match") if re.search(pattern, "eggspamsausagespam"): print("Match") else: print("No match") print(re.findall(pattern, "eggspamsausagespam")) 结果: >>> No match Match ['spam', 'spam'] >>>
在上面的示例中,match函数与模式不匹配,因为它查看字符串的开头。 search函数在字符串中找到匹配项。
函数re.finditer做与re.findall相同的事情,除了它一个返回迭代器,一个返回列表。
4.正则表达式搜索返回一个对象,并给出几种方法来给出详细信息。 这些方法包括返回匹配的字符串的组、返回第一匹配的开始和结束位置的开始和结束以及作为元组返回第一匹配的开始和结束位置的.
例如:
1
2
3
4
5
6
7
8
9import re pattern = r"pam" match = re.search(pattern, "eggspamsausage") if match: print(match.group()) print(match.start()) print(match.end()) print(match.span())
结果:
pam
4
7
(4, 7)
使用正则表达式的一个最重要的re方法是sub。
语法:
re.sub(pattern, repl, string, max=0)
此方法用替换字符串中所有匹配的内容,此方法返回修改后的字符串。
例如:
1
2
3
4
5
6import re str = "My name is David. Hi David." pattern = r"David" newstr = re.sub(pattern, "Amy", str) print(newstr)
结果:
My name is Amy. Hi Amy.
- 模式字符
模式字符串使用特殊的语法来表示一个正则表达式:
字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
多数字母和数字前加一个反斜杠时会拥有不同的含义。
标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
反斜杠本身需要使用反斜杠转义。
由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r’ ',等价于 ’ ')匹配相应的特殊字符。
下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。
1
2
3
4
5
6
7
8
9import re pattern = r"gr.y" if re.match(pattern, "grey"): print("Match 1") if re.match(pattern, "gray"): print("Match 2") if re.match(pattern, "blue"): print("Match 3")
结果:
Match 1
Match 2
接下来的两个模式字符是^和$。 它们分别匹配字符串的开始和结束。
例如:
1
2
3
4
5
6
7
8
9import re pattern = r"^gr.y$" if re.match(pattern, "grey"): print("Match 1") if re.match(pattern, "gray"): print("Match 2") if re.match(pattern, "stingray"): print("Match 3")
结果:
Match 1
Match 2
“^gr.y$” 意味着字符串应该以gr开始,然后跟随任何字符,除了换行符,以y结尾。
字符类提供了只匹配特定字符集中的一个的方法。 字符类是通过将其匹配的字符放置在方括号内而创建的。
例如:
1
2
3
4
5
6
7
8
9mport re pattern = r"[aeiou]" if re.search(pattern, "grey"): print("Match 1") if re.search(pattern, "qwertyuiop"): print("Match 2") if re.search(pattern, "rhythm myths"): print("Match 3")
结果:
Match 1
Match 2
搜索函数中的模式[aeiou]匹配包含定义的任何一个字符的所有字符串。
- 字符类
1.字符类提供了只匹配特定字符集中的一个的方法。 字符类是通过将其匹配的字符放置在方括号内而创建的。
例如:
1
2
3
4
5
6
7
8
9mport re pattern = r"[aeiou]" if re.search(pattern, "grey"): print("Match 1") if re.search(pattern, "qwertyuiop"): print("Match 2") if re.search(pattern, "rhythm myths"): print("Match 3")
结果:
Match 1
Match 2
搜索函数中的模式[aeiou]匹配包含定义的任何一个字符的所有字符串。
字符类也可以匹配字符的范围。 一些例子: 类[a-z] 匹配任何小写字母字符。 类[G-P]匹配任何大写字符从G到P。 类[0-9]匹配任何数字。 多个范围可以包含在一个类中。例如,[A-Za-z]匹配任何情况下的字母。
例如:
1
2
3
4
5
6
7
8
9mport re pattern = r"[A-Z][A-Z][0-9]" if re.search(pattern, "LS8"): print("Match 1") if re.search(pattern, "E3"): print("Match 2") if re.search(pattern, "1ab"): print("Match 3")
结果:
Match 1
上面例子中的模式匹配包含两个字母大写字母的字符串,后面跟着一个数字。
3.在字符类的开头放置一个^来反转它。 这使得它匹配除了所包含的任何字符之外的任何字符。 其他元字符,如$和.0,在字符类中没有意义。 元字符^没有意义,除非它是类中的第一个字符。
例如:
1
2
3
4
5
6
7
8
9import re pattern = r"[^A-Z]" if re.search(pattern, "this is all quiet"): print("Match 1") if re.search(pattern, "AbCdEfG123"): print("Match 2") if re.search(pattern, "THISISALLSHOUTING"): print("Match 3")
结果:
Match 1
Match 2
模式[^ A-Z]不包括大写字符串。 注意,^应该在括号内以反转字符类。
- 更多模式字符
更多的模式字符是*,+,?,{}。 这些指定重复次数。 元字符*意味着“零或更多重复以前的事情”。它试图匹配尽可能多的重复。“以前的东西”可以是一个字符,一个类,或者一组字符在括号中。
例如:
1
2
3
4
5
6
7
8
9import re pattern = r"egg(spam)*" if re.match(pattern, "egg"): print("匹配 1") if re.match(pattern, "eggspamspamegg"): print(""匹配 2") if re.match(pattern, "spam"): print(""匹配 3")
结果:
匹配 1
匹配 2
上面的例子与以“鸡蛋”开头的字符串匹配,并跟随零次或更多的“spam”。
元符号+非常类似于*,除了它意味着“一个或多个重复”,而不是“零或更多重复”。
例如:
1
2
3
4
5
6
7
8
9import re pattern = r"g+" if re.match(pattern, "g"): print("Match 1") if re.match(pattern, "gggggggggggggg"): print("Match 2") if re.match(pattern, "abc"): print("Match 3")
结果:
Match 1
Match 2
总结: *匹配前面表达式的0次或更多次。 +匹配前面表达式的1次或更多次。
模式字符?意思是“零或一次重复”。
例如:
1
2
3
4
5
6
7
8
9
10
11import re pattern = r"ice(-)?cream" if re.match(pattern, "ice-cream"): print("Match 1") if re.match(pattern, "icecream"): print("Match 2") if re.match(pattern, "sausages"): print("Match 3") if re.match(pattern, "ice--ice"): print("Match 4")
结果
Match 1
Match 2
花括号
{}可以用来表示两个数字之间的重复次数。 正则表达式{x,y}表示“在某物的X和Y重复之间”。 因此{0,1}是相同的东西吗?. 如果第一个数字没有,则取零。如果第二个数字没有,则被认为是无穷大。
例如:
1
2
3
4
5
6
7
8
9import re pattern = r"9{1,3}$" if re.match(pattern, "9"): print("Match 1") if re.match(pattern, "999"): print("Match 2") if re.match(pattern, "9999"): print("Match 3")
结果:
Match 1
Match 2
- 组
(1): 可以使用组函数访问匹配中的组的内容。 组(0)或组()的调用返回整个匹配。 群(n)的调用,其中n大于0,从左边返回第n群。 方法组()从1返回所有组。
例如:
1
2
3
4
5
6
7
8
9
10import re pattern = r"a(bc)(de)(f(g)h)i" match = re.match(pattern, "abcdefghijklmnop") if match: print(match.group()) print(match.group(0)) print(match.group(1)) print(match.group(2)) print(match.groups())
结果:
abcdefghi
abcdefghi
bc
de
(‘bc’, ‘de’, ‘fgh’, ‘g’)
从上面的示例中可以看出,组可以嵌套。
(2):可以用括号包围正则表达式的一部分来创建一个组。 这意味着一个组可以作为一个参数给元语言,例如*和?.
例如:
1
2
3
4
5
6
7
8
9import re pattern = r"egg(spam)*" if re.match(pattern, "egg"): print("Match 1") if re.match(pattern, "eggspamspamspamegg"): print("Match 2") if re.match(pattern, "spam"): print("Match 3")
(spam)表示上述示例模式中的组。
结果:
Match 1
Match 2
- 特殊符号
(1): 元字符
另一个重要元是 | 这意味着“或”,所以红蓝色匹配“红色”或“蓝色”。
例如:
1
2
3
4
5
6
7
8
9
10
11
12import re pattern = r"gr(a|e)y" match = re.match(pattern, "gray") if match: print ("Match 1") match = re.match(pattern, "grey") if match: print ("Match 2") match = re.match(pattern, "griy") if match: print ("Match 3")
结果:
Match 1
Match 2
(2):特殊序列
附加的特殊序列是 A, Z,B。 序列A和Z分别匹配字符串的开始和结束。 序列b匹配w和W 之间的空字符串,或w字符和字符串的开头或结尾。非正式地,它代表单词之间的边界。 序列B与其他地方的空字符串匹配。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18import re pattern = r"b(cat)b" match = re.search(pattern, "The cat sat!") if match: print ("Match 1") match = re.search(pattern, "We s>cat<tered?") if="" match:="" print="" ("match="" 2")="" match="re.search(pattern," "we="" scattered.")="" 3")="" <="" pre=""> <p class="resu"><b>结果:<b></b></b></p><b><b> <pre class="brush:python"> >>> Match 1 Match 2 >>> </pre> <div class="tip"> "b(cat)b"基本匹配单词“CAT”包围的单词边界。 </div> </b></b></tered?")>
(3):特殊序列
在正则表达式中可以使用各种特殊的序列。它们被写为反斜杠,后面跟着另一个字符。 一个有用的特殊序列是反斜杠和1到99之间的数字,例如,1或17。这与该数字组的表达式匹配。
例如:
1
2
3
4
5
6
7
8
9
10
11
12import re pattern = r"(.+) 1" match = re.match(pattern, "word word") if match: print ("Match 1") match = re.match(pattern, "?! ?!") if match: print ("Match 2") match = re.match(pattern, "abc cde") if match: print ("Match 3")
结果:
Match 1
Match 2
注意,“(.+)1”与“(.+)(.+)”不同,因为1指的是第一组的子表达式,即匹配的表达式本身,而不是正则表达式模式。
(4):特殊序列
更有用的特殊序列是d、s和w。 这些匹配数字、空格和单词字符分别。
例如,
w匹配字母数字及下划线。
W 匹配非字母数字及下划线
D匹配任何不是数字的东西。
d匹配任意数字,等价于 [0-9]
s匹配任意空白字符,等价于 [tnrf].
S匹配任意非空字符
例如:
1
2
3
4
5
6
7
8
9
10
11
12import re pattern = r"(D+d)" match = re.match(pattern, "Hi 999!") if match: print("Match 1") match = re.match(pattern, "1, 23, 456!") if match: print("Match 2") match = re.match(pattern, " ! $?") if match: print("Match 3")
结果:
Match 1
(D+d)匹配一个或多个非数字,后面跟着一个数字。
- 电子邮件提取
(1):为了演示正则表达式的示例用法,让我们创建一个程序来从字符串中提取电子邮件地址。 假设我们有一个包含电子邮件地址的文本:
str = “Please contact info@sololearn.com for assistance”
我们的目标是提取子字符串 “info@sololearn.com”.。 一个基本的电子邮件地址由一个单词组成,可以包括点或破折号。其次是@符号和域名(名称、点和域名后缀)。 这是构建正则表达式的基础。
pattern = r"([w.-]+)@([w.-]+)(.[w.]+)"
[w.-]+匹配一个或多个单词字符,点或破折号。
上面的正则表达式表示字符串应该包含一个单词(允许使用点号和破折号),后面跟@符号,然后是另一个类似的单词,然后是点号和另一个单词。
我们的正则表达式包含三组: 1 -电子邮件地址的第一部分。 2 -域名没有后缀。 3 -域后缀。
(2):
把它们放在一起:
1
2
3
4
5
6
7import re pattern = r"([w.-]+)@([w.-]+)(.[w.]+)" str = "Please contact info@sololearn.com for assistance" match = re.search(pattern, str) if match: print(match.group())
结果:
info@sololearn.com
如果字符串包含多个电子邮件地址,我们可以使用re.findall方法而不是re.search,来提取所有电子邮件地址。
此示例中的正则表达式仅用于演示目的。 需要更复杂的正则表达式来完全验证电子邮件地址。
在我们的例子中,为什么点字符前面有反斜杠? 把它当作一个字符看待 这是强制性的 因为它在方括号内
最后
以上就是失眠白猫最近收集整理的关于python基础全例解释的全部内容,更多相关python基础全例解释内容请搜索靠谱客的其他文章。
发表评论 取消回复