Python高级特性 ¶
类变量、类方法、静态方法 ¶
类变量
类变量是被类的所有实例共享的变量,它在类定义内部但在任何类方法外部进行定义。其主要特点为:
- 所有类的实例都能访问该变量。
- 若类变量的值被修改,所有实例访问到的都是修改后的值。
- 类变量通过类名或者实例来访问。
类方法
类方法是绑定到类而非类实例的方法,它通过@classmethod装饰器来定义,并且第一个参数通常是cls(代表类本身)。类方法的主要特点有:
- 类方法可以访问和修改类变量。
- 可以通过类名或者实例来调用类方法。
- 类方法常被用作工厂方法,用于创建类的实例。
静态方法
静态方法是类中不依赖于类或实例的方法,它通过@staticmethod装饰器来定义,并且没有类似self或cls这样的特殊第一个参数。静态方法的主要特点为:
- 静态方法不能访问或修改类变量和实例变量。
- 可以通过类名或者实例来调用静态方法。
- 静态方法通常用于执行与类相关但不依赖于类状态的实用函数。
1class Student():
2
3 # 类变量
4 student_count = 0
5
6 def __init__(self,name:str,sex:str):
7 self.name = name
8 self.sex = sex
9 Student.student_count += 1
10
11 # 类方法
12 @classmethod
13 def get_student_count(cls):
14 return cls.student_count
15
16 # 类方法
17 @classmethod
18 def from_str(cls,info:str):
19 return cls(info.split(',')[0],info.split(',')[1])
20
21 # 静态方法
22 @staticmethod
23 def get_name_len(name):
24 return len(name)
25
26stu1=Student('张三','男')
27print(Student.student_count)
28
29stu2=Student.from_str('张三,男')
30print(Student.student_count)推导式 ¶
在 Python 里,推导式是一种可以从一个或多个可迭代对象快速创建序列(像列表、字典、集合等)的语法结构。它的优点是代码简洁,执行效率较高。
- 代码简洁:只需要一行代码,就能替代多行的循环和条件语句。
- 执行效率高:推导式的执行速度通常比传统的循环语句要快。
- 可读性强:对于熟悉推导式语法的人来说,代码的意图一目了然。
列表推导式
列表推导式是最常用的推导式,其作用是快速生成列表
1[表达式 for 变量 in 可迭代对象 if 条件]字典推导式
字典推导式用于快速生成字典
1{键表达式: 值表达式 for 变量 in 可迭代对象 if 条件}集合推导式
集合推导式用于快速生成集合,它的基本语法和列表推导式类似,不过使用的是花括号{}
1{表达式 for 变量 in 可迭代对象 if 条件} 1# %%
2# 列表推导式
3nums = [1,2,3,4,5,6]
4letters = ['a','b','c','d','e','f']
5
6#---------0----------
7my_list = []
8for num in nums:
9 my_list.append(num)
10print(my_list)
11
12my_list = [num for num in nums]
13print(my_list)
14
15#---------1----------
16my_list = []
17for num in nums:
18 my_list.append(num*2)
19print(my_list)
20
21my_list = [num*2 for num in nums]
22print(my_list)
23
24#---------2----------
25my_list=[]
26for num in nums:
27 if num%2==0:
28 my_list.append(num)
29print(my_list)
30
31my_list=[num for num in nums if num%2==0]
32print(my_list)
33
34#---------3----------
35my_list=[]
36for num in nums:
37 if num%2==0:
38 my_list.append(num*2)
39 else:
40 my_list.append(num)
41print(my_list)
42
43my_list=[num*2 if num%2==0 else num for num in nums]
44print(my_list)
45
46#---------4----------
47my_list=[]
48for num1 in nums:
49 for num2 in nums:
50 my_list.append(num1+num2)
51print(my_list)
52
53my_list=[num1+num2 for num1 in nums for num2 in nums]
54print(my_list)
55
56
57# %%
58# 字典推导式
59nums = [1,2,3,4,5,6]
60letters = ['a','b','c','d','e','f']
61
62#---------0----------
63my_dict = {}
64for num,letter in zip(nums,letters):
65 my_dict[num] = letter
66print(my_dict)
67
68my_dict = {num:letter for num,letter in zip(nums,letters)}
69print(my_dict)
70
71
72# %%
73# 集合推导式
74nums = [1,2,3,1,2,3]
75
76# ----------0---------
77my_set =set()
78for num in nums:
79 my_set.add(num)
80print(my_set)
81
82my_set = { num for num in nums}
83print(my_set)生成器 ¶
在 Python 里,生成器是一种创建迭代器的高效方式,它的实现更为简洁。
生成器特性
- 惰性求值:只有在请求时才会生成值,减少了内存的占用。
- 单遍迭代:生成器是不可逆的,遍历结束后就不能再次使用。
- 状态自动保存:自动保存上一次执行的状态,简化了迭代逻辑。
停止生成器
- 使用
StopIteration异常 - 使用
return语句 - 使用生成器对象的
close()方法 - 通过外部条件控制生成器
生成器函数
借助 yield 关键字,普通函数能转变为生成器函数。每次调用 next() 时,函数会运行到 yield 处并返回值,随后暂停执行,保存当前状态。待下次调用 next(),函数会从暂停的地方继续执行。
生成器表达式
语法和列表推导式相似,不过使用的是圆括号。生成器表达式采用惰性求值,更节省内存。
1# %%
2# 生成器函数
3def square_numbers(nums:list):
4 for num in nums:
5 yield num**2
6
7# 生成器对象
8my_generator = square_numbers([1,2,3,4,5])
9print(my_generator) # <generator object square_numbers at 0x00000273F74F7D30> 打印的是内存地址
10print(next(my_generator)) # 1
11print(next(my_generator)) # 4
12print(next(my_generator)) # 9
13print(next(my_generator)) # 16
14print(next(my_generator)) # 25
15
16
17# %%
18# 生成器表达式
19my_generator = (num**2 for num in [1,2,3,4,5])
20print(my_generator) # <generator object <genexpr> at 0x0000024F2AD92A80> 打印的是内存地址
21print(next(my_generator)) # 1
22print(next(my_generator)) # 4
23print(next(my_generator)) # 9
24print(next(my_generator)) # 16
25print(next(my_generator)) # 25
26
27# %%
28# 手动停止生成器
29
30def square_numbers():
31 try:
32 yield '0'
33 yield '1'
34 raise StopIteration # 手动报错终止生成器
35 yield '2' # 这行代码不会执行
36 except GeneratorExit:
37 print('GeneratorExit')
38
39#-------------0 使用close关闭生成器------------------
40my_generator = square_numbers()
41print(next(my_generator)) # 0
42my_generator.close() # 关闭生成器,生成器会在当前暂停的 yield 处抛出 GeneratorExit 异常。
43# print(next(my_generator)) # 报错 StopIteration* 号作用 ¶
运算符
数值类型的乘法运算,平方运算
字符串 / 列表 / 元组的重复
重复生成多个相同元素
打包
函数入参定义使用 * 号可以收集为一个元组, ** 可以收集为一个字典
解包
使用 * 可以将迭代对象拆分为独立的参数,** 可以拆分包字典的键值对
1# %%
2# -----------运算符-----------
3a=5*2 # 乘号
4b=5**2 # 指数
5print(f'a:{a},b:{b}') # a:10,b:25
6
7
8# %%
9# -----------生成重复元素-----------
10a = 'ha'*4
11b=[1,3]*4
12c=(1,)*4
13print(a) # hahahaha
14print(b) # [1, 3, 1, 3, 1, 3, 1, 3]
15print(c) # (1, 1, 1, 1)
16
17# %%
18# -----------打包-----------
19# 使用*将入参打包成元组
20def fun_a(*args):
21 print(type(args)) # <class 'tuple'>
22 for arg in args:
23 print(arg) # 1 2 3
24fun_a(1,2,3)
25
26def fun_b(**kwargs):
27 print(type(kwargs)) # <class 'dict'>
28 for key,value in kwargs.items():
29 print(key,value) # a 1 b 2 c 3
30
31fun_b(a=1,b=2,c=3) # 必须传入参数名,否则会报错
32
33# %%
34# -----------解包 注意一个*和两个*区别-----------
35def fun_c(a,b):
36 print(f'a:{a},b:{b}')
37
38a=(1,2,)
39b=[5,6]
40fun_c(*a) # 使用*将元组/列表解包成多个参数,打印:a:1,b:2
41fun_c(*b) # 使用*将元组/列表解包成多个参数,打印:a:5,b:6
42print([*a,*b]) # 使用*将元组/列表解包成多个参数,打印:[1, 2, 5, 6]
43
44a={
45 'a':1,
46 'b':2
47}
48b={
49 'c':3,
50 'd':4
51}
52print({**a,**b}) # 使用**将字典解包成多个参数,打印:{'a': 1, 'b': 2, 'c': 3, 'd': 4}装饰器 ¶
装饰器(Decorator)是一种特殊的语法,用于修改或增强函数或类的功能,而无需修改其源代码。装饰器本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数。
装饰器主要是为了解决代码复用和功能增强的问题,同时保持代码的简洁性和可读性。
当使用装饰器包装函数时,被装饰后的函数会丢失原函数的一些元信息(如函数名、文档字符串、参数列表等)。functools.wraps 是一个装饰器工具,用于解决这个问题 —— 它可以将原函数的元信息 “复制” 到装饰器内部的 wrapper 函数上,确保被装饰后的函数保留原函数的身份特征。
1import time
2import functools
3# %%
4# python 中函数也是一个对象,可以作为参数传递,也可以作为返回值
5def square(x):
6 return x**2
7
8def print_fun_return(fun,x):
9 print(f'{fun.__name__} is runing')
10 return fun(x)
11
12x = print_fun_return(square,3)
13print(x) # 9
14
15# %%
16# 装饰器
17def my_decorator(fun):
18 def wrapper(*args,**kwargs):
19 start_time=time.time()
20 fun(*args,**kwargs)
21 print(f'函数 {fun.__name__} 运行时间为:{time.time() - start_time} second')
22 return wrapper
23
24def square(x):
25 time.sleep(1)
26 return x**2
27
28# 方式一
29square = my_decorator(square)
30square(2)
31
32#方式二
33@my_decorator
34def square(x):
35 time.sleep(1)
36 return x**2
37square(2)
38
39# %%
40# 装饰器生成器(带参数的装饰器)
41def my_decorator(threshold):
42 def decorator(fun):
43 def wrapper(*args,**kwargs):
44 start_time=time.time()
45 fun(*args,**kwargs)
46 if time.time()-start_time > threshold:
47 print(f'函数 {fun.__name__} 运行时间超过阈值 {threshold}')
48 return wrapper
49 return decorator
50
51def square(x):
52 time.sleep(1)
53 return x**2
54
55# 方式一
56square = my_decorator(1)(square)
57square(3)
58
59# 方式二
60@my_decorator(1)
61def square(x):
62 time.sleep(1)
63 return x**2
64square(3)
65
66# %%
67def my_decorator(fun):
68 def wrapper(*args,**kwargs):
69 start_time=time.time()
70 fun(*args,**kwargs)
71 print(f'函数 {fun.__name__} 运行时间为:{time.time() - start_time} second')
72 return wrapper
73
74@my_decorator
75def square(x):
76 time.sleep(1)
77 return x**2
78
79print(f'function name is {square.__name__}') # wrapper ,丢失了原来函数的属性
80
81# ======= 使用 functools.wraps 装饰器将原函数的元信息 “复制” 到装饰器内部的 wrapper 函数上
82def my_decorator(fun):
83 @functools.wraps(fun)
84 def wrapper(*args,**kwargs):
85 start_time=time.time()
86 fun(*args,**kwargs)
87 print(f'函数 {fun.__name__} 运行时间为:{time.time() - start_time} second')
88 return wrapper
89
90@my_decorator
91def square(x):
92 time.sleep(1)
93 return x**2
94
95print(f'function name is {square.__name__}') # wrapper ,丢失了原来函数的属性