装饰器微妙之谈

简介: 装饰器微妙之谈


简单的装饰器


def my_decorate(fun):
    def wrapper():
        print('这是个装饰器!')
        func()
     reture wapper
def greet():
 print('hello world')
greet = my_decorator(greet)
greet()
# 输出
这是个装饰器!
hello world

这段代码中变量 greet 指向了内部函数 wrapper(),而内部函数 wrapper() 中又会调用原函数 greet(),因此,最后调用 greet() 时,就会先打印 'wrapper of decorator',然后输出'hello world'。大家应该都明白!


这里的函数 my_decorator() 就是一个装饰器,它把真正需 要执行的函数 greet() 包裹在其中,并且改变了它的行为, 但是原函数 greet() 不变。


我们换一种写法,使用Python来装饰它

def my_decorator(func):   
    def wrapper():    
       print('wrapper of decorator')   
        func()  
    return wrapper
@my_decorator
def greet(): 
   print('hello world')
greet()

这里的@,我们称之为语法糖,@my_decorator就相当于 前面的greet=my_decorator(greet)语句,只不过更加 简洁。因此,如果你的程序中有其它函数需要做类似的装饰,你只需在它们的上方加上@decorator就可以了,这样 就大大提高了函数的重复利用和程序的可读性。


带有参数的装饰器


如果原函数 greet() 中,有参数需要传递给 装饰器怎么办?一个简单的办法,是可以在对应的装饰器函数 wrapper() 上,加上相应的参数,比如:


def my_decorator(func):
    def wrapper(message):
       print('wrapper of decorator')
       func(message)
     return wrapper
@my_decorator
def greet(message):
     print(message)
greet('hello world')
# 输出
wrapper of decorator
hello world


事实上,通常情况下,我们会把*args和**kwargs,作为 装饰器内部函数 wrapper() 的参数。


def my_decorator(func):
    def wrapper(*args, **kwargs):
       print('wrapper of decorator')
       func(*args, **kwargs)
    return wrapper

类装饰器


实际上,类也可 以作为装饰器。类装饰器主要依赖于函数__call_(),每当你调用一个类的示例时,函数__call__() 就会被执行一 次

class Count:
   def __init__(self, func):
       self.func = func
       self.num_calls = 0
   def __call__(self, *args, **kwargs):
       self.num_calls += 1
       print('num of calls is: {}'.format(self.num_calls))
       return self.func(*args, **kwargs)
@Count
def example():
   print("hello world")
example()
# 输出
num of calls is: 1
hello world
example()
# 输出
num of calls is: 2
hello world

这里,定义了类 Count,初始化时传入原函数 func(), 而__call__() 函数表示让变量 num_calls 自增 1,然后打印,并且调用原函数。因此,在我们第一次调用函数 example() 时,num_calls 的值是 1,而在第二次调用时, 它的值变成了 2。

相关文章
|
3月前
|
安全 程序员 编译器
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
102 11
|
5月前
|
设计模式 程序员
故意把代码写得很烂,这样的 “防御性编程“ 可取吗?
故意把代码写得很烂,这样的 “防御性编程“ 可取吗?
|
8月前
|
C#
C#的类和对象的概念学习案例刨析
【5月更文挑战第17天】C#是一种面向对象的语言,以类和对象为核心。类作为对象的模板,定义了属性(如Name, Age)和行为(如Greet)。对象是类的实例,可设置属性值。封装通过访问修饰符隐藏实现细节,如Customer类的私有name字段通过Name属性访问。继承允许新类(如Employee)从现有类(Person)继承并扩展。多态让不同对象(如Circle, Square)共享相同接口(Shape),实现抽象方法Area,提供灵活的代码设计。
79 1
|
7月前
|
Java
Java多态:如何实现“一箭双雕”的编程艺术?
【6月更文挑战第17天】Java中的多态是编程灵活性的关键,它允许通用接口处理不同类型的对象。通过抽象基类或接口,子类可以实现各自的行为。例如,在动物音乐会场景中,一个`Animal`接口让狮子、猴子和企鹅都能唱歌,调用`sing()`即自动匹配相应行为。同样,在图形绘制示例中,`Shape`基类让绘制圆形、正方形和三角形变得简单,只需调用`draw()`。多态减少了代码冗余,增强了可扩展性和可维护性,是解决需求变化的利器。
42 0
|
8月前
|
算法
犯错总结--工厂模式和策略模式傻傻没分清
犯错总结--工厂模式和策略模式傻傻没分清
68 0
犯错总结--工厂模式和策略模式傻傻没分清
|
Java 编译器
学【Java多态】-- 写高质量代码
学【Java多态】-- 写高质量代码
97 0
|
Java 编译器 C++
c++终极螺旋丸:₍˄·͈༝·͈˄*₎◞ ̑̑“类与对象的结束“是结束也是开始
c++终极螺旋丸:₍˄·͈༝·͈˄*₎◞ ̑̑“类与对象的结束“是结束也是开始
205 0
|
前端开发 JavaScript 程序员
Promise难懂?一篇文章让你轻松驾驭
Promise难懂?一篇文章让你轻松驾驭 🔥前言 前端js学习中,让大家最难受的就是异步的问题,解决异步、回调地狱等问题时你必须得学会promise,对于多数前端程序员来说promise简直就是噩梦,本篇文章就是从通俗易懂的角度做为切入点,帮助大家轻松掌握promise
Promise难懂?一篇文章让你轻松驾驭
|
Java 编译器 C++
不懂泛型,怎么装逼,一文把泛型说的明明白白,安排!!!
泛型是Java中的高级概念,也是构建框架必备技能,比如各种集合类都是泛型实现的,今天详细聊聊Java中的泛型概念,希望有所收获。记得点赞,关注,分享哦。
139 0
不懂泛型,怎么装逼,一文把泛型说的明明白白,安排!!!
|
自然语言处理 JavaScript 前端开发
【重温基础】19.闭包
【重温基础】19.闭包
157 0