Python全栈开发

Python全栈开发

一文让你彻底明白Python装饰器原理,从此面试工作再也不怕了。

一、装饰器

  装饰器可以使函数执行前和执行后分别执行其他的附加功能,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator),装饰器的功能非常强大,但是理解起来有些困难,因此我尽量用最简单的例子一步步的说明这个原理。

1、不带参数的装饰器

  假设我定义了一个函数f,想要在不改变原来函数定义的情况下,在函数运行前打印出start,函数运行后打印出end,要实现这样一个功能该怎么实现?看下面如何用一个简单的装饰器来实现:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

# 使用@语法放在函数的定义上面 相当于执行 f=outer(f),此时f赋值成为了一个新的outer函数,

# 此时f函数就指向了outer函数的返回值inner,inner是一个函数名,定义在oute函数里面

# 原来的f是函数名可简单理解为一个变量,作为outer函数的参数传递进去了 此时参数func相当于f

def outer(func):                    # 定义一个outer函数作为装饰器

    def inner():            # 如果执行inner()函数的话步骤如下:

        print(‘start‘)              # 1、首先打印了字符‘start’,

        r=func()                    # 2、执行func函数,func函数相当于def f(): print(‘中‘)

        print(‘end‘)                # 3、接着函数打印‘end’

        return r                    # 4、将func函数的结果返回

    return inner

@outer

def f():              # f=outer(f)=innner

    print(‘中‘)

f()                   # f()相当于inner(),执行inner函数的步骤看上面定义处的注释<br>#打印结果顺序为   start 中 end

2、包含任意参数的装饰器

  在实际中,我们的装饰器可能应用到不同的函数中去,这些函数的参数都不一样,那么我们怎么实现一个对任意参数都能实现功能的装饰器?还记得我写函数那篇博客中,就写一种可以接受任意参数的函数,下面来看看如何将其应用到装饰器中去  


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

#其实只要将上面一种不带参数的装饰器修改一下就可以了

#修改也很简单,只需将inner和func的参数改为 (*args,**kwargs)

#其他实现的过程和上面一种一样,就不再介绍了

def outer(func):

    def inner(*args,**kwargs):

        print(‘start‘)

        r=func(*args,**kwargs)    # 这里func(*args,**kwargs)相当于f(a,b)

        print(‘end‘)

        return r

    return inner

@outer

def f(a,b):

    print(a+b)

f(1,4)                    # f(1,4)相当于inner(1,4) 这里打印的结果为 start 5 end

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

25

26

27

28

def outer2(func2):

    def inner2(*args,**kwargs):

        print(‘开始‘)

        r=func2(*args,**kwargs)

        print(‘结束‘)

        return r

    return inner2

def outer1(func1):

    def inner1(*args,**kwargs):

        print(‘start‘)

        r=func1(*args,**kwargs)

        print(‘end‘)

        return r

    return inner1

@outer2                                # 这里相当于执行了 f=outer1(f)  f=outer2(f),步骤如下

@outer1                                #1、f=outer1(f) f被重新赋值为outer1(1)的返回值inner1,

def f():                               #    此时func1为 f():print(‘f 函数‘)

    print(‘f 函数‘)                     #2、f=outer2(f) 类似f=outer2(inner1) f被重新赋值为outer2的返回值inner2

                                       #    此时func2 为inner1函数 inner1里面func1函数为原来的 f():print(‘f 函数‘)

                                                                         

f()                                    # 相当于执行 outer2(inner1)()

>>开始                                  # 在outer函数里面执行,首先打印 ‘开始 ’

>>start                                # 执行func2 即执行inner1函数 打印 ‘start’

>>f 函数                               # 在inner1函数里面执行 func1 即f()函数,打印 ‘f 函数’

>>end                                  # f函数执行完,接着执行inner1函数里面的 print(‘end‘)

>>结束                                 # 最后执行inner2函数里面的 print(‘结束‘)

4、带参数的装饰器  

  前面的装饰器本身没有带参数,如果要写一个带参数的装饰器怎么办,那么我们就需要写一个三层的装饰器,而且前面写的装饰器都不太规范,下面来写一个比较规范带参数的装饰器,下面来看一下代码,大家可以将下面的代码自我运行一下


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

import functools

def log(k=‘‘):                                        #这里参数定义的是一个默认参数,如果没有传入参数,默认为空,可以换成其他类型的参数

    def decorator(func):

        @functools.wraps(func)                        #这一句的功能是使被装饰器装饰的函数的函数名不被改变,

        def wrapper(*args, **kwargs):

            print(‘start‘)

            print(‘{}:{}‘.format(k, func.__name__))    #这里使用了装饰器的参数k

            = func(*args, **kwargs)

            print(‘end‘)

            return r

        return wrapper

    return decorator

@log()                        # fun1=log()(fun1) 装饰器没有使用参数

def fun1(a):

    print(a + 10)

fun1(10)

# print(fun1.__name__)        # 上面装饰器如果没有@functools.wraps(func)一句的话,这里打印出的函数名为wrapper

@log(‘excute‘)                # fun2=log(‘excute‘)(fun2) 装饰器使用给定参数

def fun2(a):

    print(a + 20)

fun2(10)

  

时间: 2024-08-01 06:22:16

Python全栈开发的相关文章

Python全栈开发【基础三】

Python全栈开发[基础三]  本节内容: 函数(全局与局部变量) 递归 函数 一.定义和使用 函数最重要的是减少代码的重用性和增强代码可读性 1 def 函数名(参数): 2 3 ... 4 函数体 5 ... 6 返回值 函数的定义主要有如下要点: def:表示函数的关键字 函数名:函数的名称,日后根据函数名调用函数 函数体:函数中进行一系列的逻辑计算 参数:为函数体提供数据 返回值:当函数执行完毕后,可以给调用者返回数据. 总结使用函数的好处: 1.减少代码重用 2.保持一致性,易维护

Python全栈开发【第一篇】:初识Python

Python全栈开发[第一篇] 本节内容: Python 的种类 Python 的环境 Python 入门(解释器.编码.变量.input输入.if流程控制与缩进.while循环) if流程控制与while循环练习题 基本数据类型前引 Python 的种类 Cpython Python的官方版本,使用C语言实现,使用最为广泛,CPython实现会将源文件(py文件)转换成字节码文件(pyc文件),然后运行在Python虚拟机上. Jyhton Python的Java实现,Jython会将Pyth

Python全栈开发【基础二】

Python全栈开发[基础二] 本节内容: Python 运算符(算术运算.比较运算.赋值运算.逻辑运算.成员运算) 基本数据类型(数字.布尔值.字符串.列表.元组.字典) 编码与进制转换 Python 运算符 1.算术运算: 2.比较运算: 3.赋值运算: 4.逻辑运算:  5.成员运算: 基本数据类型 1.数字 int(整型) 1 class int(object): 2 """ 3 int(x=0) -> integer 4 int(x, base=10) -&g

python全栈开发目录

python全栈开发目录 linux命令 初识python python基础数据类型 函数编程.set.深浅拷贝 内置函数 文件操作 装饰器 迭代器和生成器 常用模块 初识类和对象 类和对象(进阶) 反射 异常处理 socket.IO多路复用 线程.进程.协程 HTML CSS JavaScript DOM文档操作 jQuery实例 web框架本质 Tornado mysql基础 mysql进阶 ..... 基本算法 递归--二分法查找 冒泡排序 更多 线程池

Python全栈开发【基础四】

Python全栈开发[基础四] 本节内容: 匿名函数(lambda) 函数式编程(map,filter,reduce) 文件处理 匿名函数 lambda表达式:对于简单的函数,存在一种简便的表示方式,即lambda表达式 1 #这段代码 2 def calc(n): 3 return n**n 4 print(calc(10)) 5 6 #换成匿名函数 7 calc = lambda n:n**n 8 print(calc(10)) 匿名函数主要是和其它函数搭配使用 举例: 1 ########

自学Python全栈开发第一次笔记

我已经跟着视频自学好几天Python全栈开发了,今天决定听老师的,开始写blog,听说大神都回来写blog来记录自己的成长. 我特别认真的跟着这个视频来学习,(他们开课前的保证书,我也写了一份,哈哈哈...)我现在是准大学生,准备学习编程,日后做一个程序员,哈哈哈.听说程序员很苦逼,不过貌似挣得也很多啊.并且我貌似也只喜欢计算机这个方面,所以我想在这个行业发光. 前些天学习了一些Linux一些命令: pwd     查看你当前所在的目录  /root=计算机/E盘 /    是根目录 cd(ch

Python 全栈开发:python列表List

列表 列表是python中经常使用的数据类型,用于存放多个值. 表现形式:在[ ]内用逗号分隔,可以存放n个任意类型的值 eg: #单一类型 users=['yangli','yite','fixd'] #多类型,列表嵌套 users=['room01',['yangli',20,'音乐'],['yite',20,'篮球'],] 列表常用方法 和 函数 方法 函数 常用的操作 eg: len(list) #len(list) 计算列表的长度 ls = ['a','b','c','d'] leng

Python 全栈开发:python元组tuple

元组 什么是元组:"元组就是一个不可变的列表" (并不是列表,只是为了便于记忆) 用途:用于存放多个值,只能读不能二次赋值 表现形式:小括号()中间以逗号分割各个元素 eg: tuples = ('a','b','c','d') 元组常用的操作 生成一个简单的元组 tuples = tuple(range(5)) print(tuples) #结果(0, 1, 2, 3, 4) len(tuple) #计算元组长度 tuples = (0, 1, 2, 3, 4) print(len(

python全栈开发-Day8 函数基础

python全栈开发-Day8 函数 一 .引子 1. 为何要用函数之不用函数的问题 #1.代码的组织结构不清晰,可读性差 #2.遇到重复的功能只能重复编写实现代码,代码冗余 #3.功能需要扩展时,需要找出所有实现该功能的地方修改之,无法统一管理且维护难度极大  2. 函数是什么? 针对二中的问题,想象生活中的例子,修理工需要实现准备好工具箱里面放好锤子,扳手,钳子等工具,然后遇到锤钉子的场景,拿来锤子用就可以,而无需临时再制造一把锤子. 修理工===>程序员 具备某一功能的工具===>函数