Python编程 IV 数据与函数扩展

python中,定义了一些有用的特性帮助编程人员丰富功能的处理过程

装饰器

在 类设计思想中 有一条开闭原则 “对扩展开放,对修改关闭”。 在前面的内容中,我们已经讨论过一些 python对于封装特性的处理。 这里的装饰器就是用于对已定义类进行功能扩展的一种方法。

如property 通过为方法装饰property,可以将方法伪装成属性调用,而不是直接对类中的属性进行操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class person :
def __init__(self,name):
self.__name = name

@property
def name(self):
return self.__name
@name.setter
def name(self,name):
self.__name = name


preson1 = person("wang")
print(preson1.name)
# output wang
preson1.name = "zhao"
print(preson1.name)
# output zhao

由这个例子可以看出,通过@property ,并未对原始类进行修改,但是对它最终行为产生了影响

如何定义一个装饰器

装饰器的本质是定义一个函数 接收一个函数作为参数, 并在函数内部再定义一个函数,将接收进来的参数在该函数内执行,最终返回该函数

因为之前讨论过 “__call__” 方法在接收参数这方面和函数一致,所以有两种定义方法

装饰器的基础定义 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def add_hello(func):                              # 定义装饰函数
def wapper(*args ,**kwargs) : # 定义内部函数, 在这一层接收原函数的参数
print("hello user") # 执行函数前的预处理
func(*args ,**kwargs) # 函数执行
print("goodbye user") # 函数结束
return wapper # 将构建的函数作为返回值

@add_hello # 将装饰器添加在函数定义上
def base_function(parameter):
print(f"this is a parmeter {parameter}")
print("this is a base function")


base_function("hello")

# 执行
# hello user # 预处理
# this is a parmeter hello # 函数代码块执行
# this is a base function # 函数代码块执行
# goodbye user # 结束

扩展1 : 装饰器本身也可以接收参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def add(*outter_args,**outter_kwargs):            # 定义装饰函数,这一层接收装饰器参数
def add_hello(func): # 定义内部函数, 这一层接收函数
def wapper(*args ,**kwargs) : # 定义实际的装饰器函数, 接收函数的变量
print(outter_args[0]) # 打印接收到的装饰器参数
print("hello user") # 预处理
func(*args ,**kwargs) # 函数执行
print("goodbye user") # 结束
return wapper # 返回装饰器函数
return add_hello # 返回外层函数

@add("hi") # 添加带参装饰器
def base_function(parameter):
print(f"this is a parmeter {parameter}")
print("this is a base function")


base_function("hello")

# 输出
# hi # 接收到的装饰器参数
# hello user # 预处理
# this is a parmeter hello # 函数代码执行
# this is a base function # 函数代码执行
# goodbye user # 结束

扩展2:装饰器装饰在类上

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
def add(*outter_args,**outter_kwargs):
def add_hello(func):
def wapper(*args ,**kwargs) :
print(outter_args[0])
print("hello user")
m = func(*args ,**kwargs) # 主要要将实例创建的对象返回,这里执行的实际上是对象的初始化
print("goodbye user")
return m
return wapper
return add_hello

@add("hi")
class person :
def __init__(self):
print("class person is on initing")
pass
def __call__(self,message):
print(message)

p = person()
p("hello")

# 输出
# hi # 打印接收到的装饰器参数
# hello user # 预处理
# class person is on initing # 类调用
# goodbye user # 结束
# hello # 实例的调用

装饰器是一种语法糖,其本质是通过多层嵌套函数实现的运行时函数增强机制。

顺序是 定义函数传入装饰器参数-定义函数传入函数-定义函数传入原函数参数-定义函数传入原函数。然后再逐层返回,另外就是用到了python的作用域机制,即定义的内部函数对外部的局部变量是可以访问的

扩展3 :使用类定义装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class add :
def __init__(self,name): # 接收的装饰器 参数 相当于执行了初始化
self.name = name
def __call__(self,func): # 接收函数
def wapper(*args,**kwargs): # 接收函数的参数
print(self.name) # 获取到的实例属性
print("hello user") # 预处理
func(*args) # 执行函数
print("goodby user") # 结束
return wapper # 返回函数

@add("codfish")
def base_function(parameter):
print(f"this is a parmeter {parameter}")
print("this is a base function")

base_function("base_parameter")

# 输出
# codfish # 接收到的装饰器参数
# hello user # 预处理
# this is a parmeter base_parameter # 函数执行
# this is a base function # 函数执行
# goodby user # 结束

可以看到以类作为装饰器的大体逻辑是一致的 无非就是 函数和参数传入位置发生了变化

迭代器

迭代器是一种让创建的实例获得如列表或者元组等结构一样,允许使用for 循环遍历整个数据结构中的元素的特性。其本质是通过实现两个魔术方法实现的 “__iter__” 和 “__next__”

“__iter__” 会返回一个可迭代对象

“__next__” 则是会获取可迭代对象中的下一个值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class num_group :
def __init__(self):
self.num = 0

def __iter__(self):
return self

def __next__(self):
self.num+=1
if self.num > 10 :
raise StopIteration
return self.num


a = num_group()
print(next(a)) # 既可以通过next(a) 获取迭代对象中的下一个返回
for i in a: # 也可以通过遍历来完成迭代对象的值遍历
print(i)

生成器

与 通过列表中查询数据不同,Python 还提供了一个组件 yield来生成数据。

在一个函数中定义了yield关键字后,该函数被称为生成器。

当执行到该函数时,会返回一个生成器对象。这个生成器对象会保留其执行所使用的栈帧结构。

当运行到yield关键字时,会将值返回,生成器对象暂停,并完整保留当前的执行状态。当生成器对象的代码执行完毕后,生成器对象会退出等待GC回收。

1
2
3
4
5
6
7
8
9
10
11
def count(num=0):
while True :
yield num # 声明了yield,python 会将这个函数作为生成器处理
if num > 10 :
return 100
num+=1

b = count() # 执行函数返回一个生成器对象

for i in b :
print(i) # for 循环会持续调用生成器的 __next__() 方法,直到捕获到 StopIteration 异常,表示迭代结束。

内建的作用域设置函数 setattr,getattr,delattr

在python中命名空间决定了一个对象都可以访问哪些对象,而通过setattr,getattr和delattr 可以直接对对象的命名空间进行操作,来修改对象的访问权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class person:                                     # 定义一个类
def __init__(self,name): # 重写构造函数
self.name = name

delattr(person,"__init__") # 删除person类中的构造函数定义
someone = person() # 对象正常创建

class person: # 定义空累 person
pass

def __init__(self,name): # 定义全局方法 __init__
self.name = name
setattr(person,"__init__",__init__) # 将方法设置到person的命名空间
c = person("wang") # 正常实例化
print(c.name) # 输出 “wang”

从这里我们可以看出 python中的类和方法的关系是松散绑定的。

并且还是实时的

1
2
3
4
5
6
7
8
class person:
pass
person1 = person("wang") # person1创建失败
def __init__(self,name):
self.name = name
setattr(person,"__init__",__init__)
person2 = person("wang") # person2创建成功
print(c.name)

由此我们也可以看出python 在执行阶段是逐行解释的

利用这个特性,可以对python的代码进行流程控制等操作


Python编程 IV 数据与函数扩展
http://gadoid.io/2025/04/15/Python编程-IV-数据与函数扩展/
作者
Codfish
发布于
2025年4月15日
许可协议