Python函数装饰器的使用详解

目录
  • 装饰器
    • 装饰器的定义
    • 装饰器的意义
    • 装饰器的使用
      • 无参装饰器
      • 有参装饰器
  • 实例练习
  • 总结

装饰器

装饰器的定义

关于装饰器的定义,我们先来看一段github上大佬的定义:

Function decorators are simply wrappers to existing functions.
In the context of design patterns,decorators dynamically alter the functionality of a function, method or class without having to directly use subclasses.
This is ideal when you need to extend the functionality of functions that you don’t want to modify.
We can implement the decorator pattern anywhere, but Python facilitates the implementation by providing much more expressive features and syntax for that.

这段话的最主要的意思就是:

函数装饰器是给已有函数的简单容器。
在原有的代码环境下,它能够动态地改变一个函数的功能,或者不直接使用子类而改变方法和类。
当你不想修改源代码但又想实现功能上的扩充的时候,这是一个不错的方法。
我们可以在任何情况下使用装饰器样式,同时Python通过提供更多强力的属性和语法来帮助装饰器的使用。

装饰器的意义

在上文之中其实我们已经知道了装饰器的意义,
可以不需要修改源代码就能够直接做到功能的扩充,但是为此我们需要付出的是更多的编写时间,
而且更为重要的是,通过修改源码实现功能的增加往往会改变接口传递的参数,可一个项目之中往往存在许多接口这也代表着你可能需要多次更改接口参数,
这个工作量,我们可不干!

装饰器的使用

无参装饰器

无参装饰器是最为基础的装饰器,
其根本原因在于装饰的函数对象不需要仍和的参数;
接下来示范一下最简单的装饰器是如何实现的:

def greeting():						# 定义一个最基本的无参函数
    return "Hello,读者老爷们!"
# 现在我需要实现的要求是:让输出的内容变为<p>"Hello,读者老爷们"<p>
# 在不直接更改greeting函数的前提下,我们需要使用无参装饰器
def decorator_p(func):				# 用于接收一个函数
	def wrapper():
		return f'<p>{func()}<p>'
	return wrapper
decorator = decorator_p(greeting)		# 调用decorator_p,并且用一个decorator接收返回值
print(decorator())

<p>Hello,读者老爷们!<p>
以上就是输出的结果

但是这个结果我其实并不满意,
因为完成了功能附加之后我们居然还需要再使用decorator = decorator_p(greeting)来接收一下,而且这样的话调用方式就不再是原本的greeting()了,而是decorator()
这两者对于追求高效优雅的Python来说已经提供解决方法了,
让我娓娓道来:

# 针对于调用方式而言,我们首先想到的解决方法是
greeting = decorator_p(greeting)		# 将原本的greeting函数传给decorator_p,而重命名
print(greeting())						# 输出结果与原来相同
但这个仍然可以改进,这就要使用到Python提供的@,
但使用这种方法必须注意书写的顺序,因此代码必须这样更改:
def decorator_p(func):
    def wrapper():
        return f'<p>{func()}<p>'
    return wrapper

@decorator_p					# 效果等同于 greeting = decorator_p(greeting)
def greeting():
    return "Hello,读者老爷们!"
print(greeting())

<p>Hello,读者老爷们!<p>

得到的结果是我们想要的,但使用这种方法顺序格外重要,
如果这样书写,则会给出报错:

@decorator_p						#使用这个@后,将会开始向上寻找decorator_p这个函数
def greeting():
    return "Hello,读者老爷们!"
print(greeting())

def decorator_p(func):
    def wrapper():
        return f'<p>{func()}<p>'
    return wrapper

NameError: name ‘decorator_p’ is not defined

给出的报错原因是因为没有找到decorator_p这个函数,
可明明我们已经完成这个函数的定义了,
所以我们可以得到的结论便是:

当使用@时,就会开始向上寻找函数,当找不到函数的时候就会报错

有参装饰器

接下来介绍一下有参装饰器,就是指需要传递参数的装饰器,
上文之中其实已经介绍过了关于无参装饰器的使用,而有参装饰器也并没有多难,
来一个示范:

def decorator(func):
    def wrapper(name):
        return f'<p>{func(name)}<p>'
    return wrapper

@decorator
def greeting(name):
    return f"Hello,{name}!"
print(greeting('读者老爷'))		# 传递一个参数

<p>Hello,读者老爷!<p>

实例练习

OK,经过上文介绍所有读者应该又会处于似懂非懂的状态,
那么秉持一文一练的理念,我们接下来将通过编写登录功能,仔细看一下使用装饰器和不适用装饰器的区别。
在开始之前,我创建了一个文本文件夹,将会用于模拟用户储存的信息,内容如下:

sign_in.txt
Joseph:Jostar
Jonasen:Jostar
Kujo:Jotaro
Jolin:Kujo
Diavollo:Doppio

需求清单:
1)用户账户只能够由数字和英文组成,长度不超过16字符;
2)用户密码只能够由数字和英文组成,长度不超过16字符;
3)用户拥有4次输入的机会。

# 不使用任何函数
# 无装饰器 登录功能
count = 1				# 用于计算使用次数
while count < 5:
    user_account = input('请输入你的账号')
    if user_account.isalnum() and len(user_account) <= 16:		# 判断账号长度和组成
        user_keyword = input('请输入你的密码')
        if user_keyword.isalnum() and len(user_keyword) <= 16:	# 判断密码的长度和组成
            with open('sign_in.txt','r') as file:				# 打开登录文件核对登录信息
                for line in file:
                    r_name, r_keyword = line.strip().split(':')
                    if r_name == user_account and r_keyword == user_keyword:
                        print('登录成功')
                        break
                else:
                    count += 1
                    print(f'账号密码不匹配,还剩下{5-count}次机会')
                    continue
                break
        else:
            count += 1
            print(f'密码输入错误,还剩下{5-count}次机会')
            continue
    else:
        count += 1
        print(f'输入账号错误,还剩下{5-count}次机会')
        continue
else:
    print('机会已用完')

程序员之间总是流传着这么一个梗,
开发总是会看着一串代码愣愣出神说道:“这究竟是谁写的代码,像坨屎。”
然后过了良久突然说“好像是我自己写的。”

接下来我们需要做的就是改良,使用装饰器将其改良,
我们的源代码将其固定成这样:

# 只是单纯的用户输入,
# 而后我们要在此基础上不断优化,为其添加上判断长度、限制次数的功能
def input_signup():
    user_name = input('请输入账户名字')
    user_keyword = input('请输入账户密码')
    return user_name, user_keyword
def passing_func(func1, func2, func3):
    def wrapper(func4):
        def decorator():
            count = 1
            while count < 5:
                name, keyword = func4()
                check = func1(name, keyword)
                if check is not True:
                    count += 1
                    print(f'你还剩下{5-count}次登录机会')
                    continue
                check = func2(name, keyword)
                if check is not True:
                    count += 1
                    print(f'你还剩下{5-count}次登录机会')
                    continue
                check = func3(name, keyword)
                if check is not True:
                    count += 1
                    print(f'你还剩下{5 - count}次登录机会')
                    continue
                else:
                    break
        return decorator
    return wrapper

def limit_len(name, keyword, length=16):
    '''
    用于判断用户名字和密码的长度是否符合标准
    :param   name:用于接受用户的名字
    :param   keyword:用于接受用户的密码
    :param   length:默认参数为16
    :return: check:用于判断输入是否符合长度标准,详细请见装饰器中的使用
    '''

    check = True
    if len(name) > length or len(keyword) > length:
        print('账号名或密码长度不符合规范')
        check = False
        return check
    return check

def limit_composition(name, keyword):
    '''
    用于判断用户名字和密码的组成是否符合标准
    :param   name:用于接受用户的名字
    :param   keyword:用于接受用户的密码
    :return: check:用于判断输入是否符合长度标准,详细请见装饰器中的使用
    '''

    check = True
    if name.isalnum() is not True or keyword.isalnum() is not True:
        print('账号名或密码组成不符合规范')
        check = False
        return check
    return check

def verify_useinfo(name, keyword):
    '''
    用于检验用户输入的账号和密码是否符合文件中储存的
    :param   name:用于接受用户的名字
    :param   keyword:用于接受用户的密码
    :return: check:用于判断输入是否符合长度标准,详细请见装饰器中的使用
    '''
    check = True
    with open('sign_in.txt','r') as file:
        for line in file:
            r_name, r_keyword = line.strip().split(':')
            if r_name == name and r_keyword == keyword:
                print('登录成功,欢迎使用')
                return check
        else:
            check = False
            print('账号密码错误,请重新输入')
            return check

@passing_func(limit_len, limit_composition, verify_useinfo)
def input_signup():
    user_name = input('请输入账户名字')
    user_keyword = input('请输入账户密码')
    return user_name, user_keyword

以上就是关于装饰器的所有内容了,
希望能够对所有读者有所帮助。

总结

到此这篇关于Python函数装饰器的使用详解的文章就介绍到这了,更多相关Python函数装饰器内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2022-01-12

Python 函数装饰器详解

目录 使用场景 授权(Authorization) 日志(Logging) 带参数的装饰器 在函数中嵌入装饰器 装饰器类 总结 装饰器(Decorators)是 Python 的一个重要部分.简单地说:他们是修改其他函数的功能的函数.他们有助于让我们的代码更简短,也更Pythonic(Python范儿).大多数初学者不知道在哪儿使用它们,所以我将要分享下,哪些区域里装饰器可以让你的代码更简洁.首先,让我们讨论下如何写你自己的装饰器. 这可能是最难掌握的概念之一.我们会每次只讨论一个步骤,这样你能

Python函数装饰器的使用教程

典型的函数装饰器 以下示例定义了一个装饰器,输出函数的运行时间: 函数装饰器和闭包紧密结合,入参func代表被装饰函数,通过自由变量绑定后,调用函数并返回结果. 使用clock装饰器: import time from clockdeco import clock @clock def snooze(seconds): time.sleep(seconds) @clock def factorial(n): return 1 if n < 2 else n*factorial(n-1) if _

如何实现一个python函数装饰器(Decorator)

装饰器本质上是一个 Python 函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象.它经常用于为已有函数/类添加记录日志.计时统计.性能测试等. 首先定义一个倒计时函数,这个函数的功能非常简单,就是把n从当前值减少到0. def countdown(n): while n > 0: print('time' + str(n)) n -= 1 print(countdown.__name__) 程序输出: countdown 1.为函数增

Python&nbsp;函数装饰器应用教程

目录 一.什么是函数装饰器 二.函数装饰器的执行时机 三.变量作用域 四.闭包 五.保留函数的元数据 七.使用lru_cache缓存函数执行结果 八.使用singledispatch实现泛型函数 九.通过参数控制函数装饰器的行为 一.什么是函数装饰器 1.函数装饰器是Python提供的一种增强函数功能的标记函数: 2.装饰器是可调用的函数对象,其参数是另一个函数(被装饰的函数): 我们可以使用修饰器来封装某个函数,从而让程序在执行这个函数之前与执行完这个函数之后,分别运行某些代码.这意味着,调用

Python 中的函数装饰器和闭包详解

函数装饰器可以被用于增强方法的某些行为,如果想自己实现装饰器,则必须了解闭包的概念. 装饰器的基本概念 装饰器是一个可调用对象,它的参数是另一个函数,称为被装饰函数.装饰器可以修改这个函数再将其返回,也可以将其替换为另一个函数或者可调用对象. 例如:有个名为 decorate 的装饰器: @decorate def target(): print('running target()') 上述代码的写法和以下写法的效果是一样的: def target(): print('running targe

Python高阶函数与装饰器函数的深入讲解

本文主要介绍的是Python高阶函数与装饰器函数的相关内容,分享给大家,下面话不多说了,来一起看看详细的介绍吧 高阶函数 1.可以使用函数对象作为参数的函数 2.或可以将函数作为返回值的函数 3.函数对象:定义好的函数,使用函数名调用(不要加括号) #将函数作为参数的高阶函数,通过传入不同的函数,可以使执行的结果不同 4.内置高阶函数 (1)map数据映射函数 map函数接收的是两个参数,一个函数,一个序列,其功能是将序列中的值处理再依次返回至列表内.其返回值为一个迭代器对象 (2)reduce

JS装饰器函数用法总结

在 ES6 中增加了对类对象的相关定义和操作(比如 class 和 extends ),这就使得我们在多个不同类之间共享或者扩展一些方法或者行为的时候,变得并不是那么优雅.这个时候,我们就需要一种更优雅的方法来帮助我们完成这些事情. 什么是装饰器 Python 的装饰器 在面向对象(OOP)的设计模式中,decorator被称为装饰模式.OOP的装饰模式需要通过继承和组合来实现,而Python除了能支持 OOP 的 decorator 外,直接从语法层次支持 decorator. 如果你熟悉 p

详谈Python高阶函数与函数装饰器(推荐)

一.上节回顾 Python2与Python3字符编码问题,不管你是初学者还是已经对Python的项目了如指掌了,都会犯一些编码上面的错误.我在这里简单归纳Python3和Python2各自的区别. 首先是Python3-->代码文件都是用utf-8来解释的.将代码和文件读到内存中就变成了Unicode,这也就是为什么Python只有encode没有decode了,因为内存中都将字符编码变成了Unicode,而Unicode是万国码,可以"翻译"所以格式编码的格式.Python3中

Python高阶函数、常用内置函数用法实例分析

本文实例讲述了Python高阶函数.常用内置函数用法.分享给大家供大家参考,具体如下: 高阶函数: 允许将函数作为参数传入另一个函数: 允许返回一个函数. #返回值为函数的函数 sum=lambda x,y:x+y sub=lambda x,y:x-y calc_dict={"+":sum,"-":sub} def calc(x): return calc_dict[x] print(calc('-')(5,6)) print(calc('+')(5,6)) #参数

详解Python高阶函数

本文要点 1.什么是高阶函数 2.python中有哪些常用的高阶函数 什么是高阶函数? 在了解什么是高阶函数之前,我们来看几个小例子.我们都知道在 python 中一切皆对象,函数也不例外.比如求绝对值函数 abs,我们可以用一个变量 f 指向 abs 函数,那么当调用 f() 的时候可以得到和 abs() 一样的效果,这说明变量可以指向函数! 同理我们将 abs 指向另一个函数 abs = len,那么 abs 将不再是求绝对值的函数了,abs指向的是求长度的 len 函数.这说明函数名其实就

Flask框架实现给视图函数增加装饰器操作示例

本文实例讲述了Flask框架实现给视图函数增加装饰器操作.分享给大家供大家参考,具体如下: 在@app.route的情况下增加装饰器的写法: from flask import Flask,request,render_template,redirect,session,url_for,views from flask import render_template app = Flask(__name__) #实例化flask对象 app.debug = True #能够随时更改自动重启,不加的

JavaScript装饰器函数(Decorator)实例详解

本文实例讲述了JavaScript装饰器函数(Decorator).分享给大家供大家参考,具体如下: 装饰器函数(Decorator)用于给对象在运行期间动态的增加某个功能,职责等.相较通过继承的方式来扩充对象的功能,装饰器显得更加灵活,首先,我们可以动态给对象选定某个装饰器,而不用hardcore继承对象来实现某个功能点.其次:继承的方式可能会导致子类繁多,仅仅为了增加某一个单一的功能点,显得有些多余了. 下面给出几个常用的装饰器函数示例,相关代码请查看github. 1 动态添加onload

python 一篇文章搞懂装饰器所有用法(建议收藏)

01. 装饰器语法糖 如果你接触 Python 有一段时间了的话,想必你对 @ 符号一定不陌生了,没错 @ 符号就是装饰器的语法糖. 它放在一个函数开始定义的地方,它就像一顶帽子一样戴在这个函数的头上.和这个函数绑定在一起.在我们调用这个函数的时候,第一件事并不是执行这个函数,而是将这个函数做为参数传入它头顶上这顶帽子,这顶帽子我们称之为装饰函数 或 装饰器. 你要问我装饰器可以实现什么功能?我只能说你的脑洞有多大,装饰器就有多强大. 装饰器的使用方法很固定: 先定义一个装饰函数(帽子)(也可以

分析Python中设计模式之Decorator装饰器模式的要点

先给出一个四人团对Decorator mode的定义:动态地给一个对象添加一些额外的职责. 再来说说这个模式的好处:认证,权限检查,记日志,检查参数,加锁,等等等等,这些功能和系统业务无关,但又是系统所必须的,说的更明白一点,就是面向方面的编程(AOP). 在Python中Decorator mode可以按照像其它编程语言如C++, Java等的样子来实现,但是Python在应用装饰概念方面的能力上远不止于此,Python提供了一个语法和一个编程特性来加强这方面的功能.Python提供的语法就是

深入理解python中的闭包和装饰器

python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure). 以下说明主要针对 python2.7,其他版本可能存在差异. 也许直接看定义并不太能明白,下面我们先来看一下什么叫做内部函数: def wai_hanshu(canshu_1): def nei_hanshu(canshu_2): # 我在函数内部有定义了一个函数 return canshu_1*canshu_2 return

python中property和setter装饰器用法

作用:调用方法改为调用对象, 比如 : p.set_name() 改为 p.set_name 区别:前者改变get方法,后者改变set方法 效果图: 代码: class Person: def __init__(self,name): self._name = name def get_name(self): return self._name def set_name(self,name): self._name = name p = Person('小黑') print(p.get_name