python中的对象
1 2 3 4 5 6 7 8 9 10 11 12 def apple (): print ("there is an apple" ) apple apple() obj = apple obj()
注意这里apple 和 apple() 的区别
apple(函数对象) 定义 :apple 是函数对象的引用。
在 Python 中,函数是第一类对象(First-class object),意味着它们可以被赋值给变量、作为参数传递、作为返回值返回等。
apple 本质上是一个指向函数对象的引用,它存储了函数的定义(包括函数名、参数列表、函数体等信息)。
调用 type(apple) 返回 <class ‘function’>,说明 apple 是一个函数类型的对象。
apple()(函数调用) 定义 :apple() 表示调用 apple 函数。
当在函数名后加上括号 () 时,Python 解释器会执行该函数的代码块。 函数调用的过程包括:
创建一个新的作用域(局部命名空间)。
执行函数体中的代码。
如果函数中有 return 语句,则返回指定的值;否则默认返回 None。
在这个例子中,apple() 执行了函数体中的 print(“there is an apple”),因此打印了消息。
定义一个log函数能够记录日志
直接在log函数中打印日志,并且执行传入的函数func
但这样会将原来直接执行apple()改为需要执行log(apple)
1 2 3 4 5 6 7 8 def apple (): print ("there is an apple" ) def log (func ): print ("this is log" ) func() log(apple)
保证继续apple() 1 2 3 4 5 6 7 8 9 def apple (): print ("there is an apple" ) def log (func ): print ("this is log" ) func() apple = log(apple) apple()
注意这里log(apple)是函数调用,会去执行log函数,由于该函数没有返回值,log(apple)返回为None,也就是appple = None, 再次执行appple()则会报错。
为了解决这个问题,正确的写法应该是在log中返回一个函数,而不是去执行该函数。
1 2 3 4 5 6 7 8 9 10 def apple (): print ("there is an apple" ) def log (func ): print ("this is log" ) return func apple = log(apple) apple()
假如apple函数需要传入参数 1 2 3 4 5 6 7 8 9 10 11 12 def apple (count ): if count == 1 : print ("there is an apple" ) elif count > 1 : print (f"there are {count} apples" ) def log (func ): print ("this is log" ) return func apple = log(apple(count)) apple()
按照之前的逻辑,直接像上面这样写肯定不行,因为apple(count)会直接执行该函数,那么log(apple(count))中log函数的参数便不再是函数了,而是apple(count)的结果。
同样的逻辑,需要将保证apple为一个函数,且需要能接受参数,则在原来的log里面先定义一个能接受任意参数的help函数,将它返回。
help函数里面应该写什么呢?
首先它需要记录log,并且根据传入的参数直接将其作为func函数的参数,并返回。当然在这个例子中,这里不返回直接执行也是可以的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def apple (count ): if count == 1 : print ("there is an apple" ) elif count > 1 : print (f"there are {count} apples" ) def log (func ): def help (*arg, **args ): print ("this is log" ) return func(*arg, **args) return help apple = log(apple) apple(5 )
装饰器 为了简化apple = log(apple)这个操作,python给出了一个简单的语法规则“@”将该步骤自动化,也就是“装饰器”。
注意这里装饰器需要先定义再使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 def log (func ): def help (*arg, **args ): print ("this is log" ) return func(*arg, **args) return help @log def apple (count ): if count == 1 : print ("there is an apple" ) elif count > 1 : print (f"there are {count} apples" ) apple(5 )
装饰器参数 如果装饰器也需要添加参数怎么办呢。那么在外层再封装一层函数即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 def log (level ): def log_decorator (func ): def help (*arg, **args ): print (f"Logging level: {level} " ) print ("this is log" ) return func(*arg, **args) return help return log_decorator @log("info" ) def apple (count ): if count == 1 : print ("there is an apple" ) elif count > 1 : print (f"there are {count} apples" ) apple(5 )
类装饰器 python基础
:::success 类装饰器本质是通过类的魔术方法__call__来实现上述函数装饰器的类似功能,但使用类装饰器最大的好处是可以保存实例对象(注意不是类)的历史数据。
:::
类装饰器 :类装饰器通过定义一个类来实现装饰器功能。通常需要实现 __init__
和 __call__
方法:
__init__
:初始化装饰器,接收被装饰的函数作为参数。
__call__
:使类的实例可以像函数一样被调用,从而实现对目标函数的包装。
类装饰器的基本语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Decorator : def __init__ (self, func ): self.func = func def __call__ (self, *args, **kwargs ): print ("Before function call" ) result = self.func(*args, **kwargs) print ("After function call" ) return result @Decorator def my_function (): print ("Function executed" ) my_function()
输出:
1 2 3 Before function call Function executed After function call
类装饰器的工作原理
装饰器的执行时机 :
当使用 @Decorator
装饰函数时,Python 会将被装饰的函数传递给装饰器类的构造函数(__init__
)。
被装饰的函数会被保存为类的实例属性(如 self.func
)。
调用被装饰的函数 :
当调用被装饰的函数时,实际上是调用了装饰器类的 __call__
方法。
在 __call__
方法中,可以执行额外的逻辑,然后调用原始函数。
类装饰器的应用场景
类装饰器适用于以下场景:
需要维护状态的装饰器 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class CountCalls : def __init__ (self, func ): self.func = func self.call_count = 0 def __call__ (self, *args, **kwargs ): self.call_count += 1 print (f"Call count: {self.call_count} " ) return self.func(*args, **kwargs) @CountCalls def say_hello (): print ("Hello!" ) say_hello() say_hello()
- 类装饰器可以通过实例属性存储状态,而函数装饰器通常需要通过闭包实现类似功能。
复杂的装饰逻辑 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class LoggingDecorator : def __init__ (self, func ): self.func = func def log (self, message ): print (f"[LOG] {message} " ) def __call__ (self, *args, **kwargs ): self.log("Before function call" ) result = self.func(*args, **kwargs) self.log("After function call" ) return result @LoggingDecorator def add (a, b ): return a + b print (add(3 , 5 ))
- 如果装饰器需要处理复杂的逻辑,类装饰器可以通过方法分解逻辑,使代码更清晰。
参数化的装饰器 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Repeat : def __init__ (self, times ): self.times = times def __call__ (self, func ): def wrapper (*args, **kwargs ): for _ in range (self.times): func(*args, **kwargs) return wrapper @Repeat(times=3 ) def greet (name ): print (f"Hello, {name} !" ) greet("Alice" )
和函数的过程类似。需要再外面再封装一层。实现过程为
实例化类对象,传入times参数为3
调用__call__方法,传入func函数
类装饰器与函数装饰器的对比
特性
类装饰器
函数装饰器
实现方式
使用类和 __call__
方法
使用嵌套函数
状态管理
可以通过实例属性轻松管理状态
需要通过闭包管理状态
复杂逻辑分解
可以通过类的方法分解复杂逻辑
所有逻辑通常集中在一个函数中
适用场景
需要维护状态或逻辑较复杂的装饰器
简单装饰器
注意事项
确保实现 __call__
方法 :
类装饰器必须实现 __call__
方法,否则无法像函数一样调用。
避免不必要的实例化 :
如果装饰器不需要维护状态,函数装饰器可能更简单高效。
兼容性 :
类装饰器和函数装饰器在功能上是等价的,选择哪种方式取决于具体需求。
//