本节内容

  1. 定义
  2. 原则
  3. 实现装饰器的储备知识
  4. 函数及变量
  5. 高阶函数

一、定义

1、装饰器:本质是函数。

2、功能:用来装饰其他函数,顾名思义就是,为其他的函数添加附件功能的。

二、原则

  1. 不能修改被装饰函数的源代码
  2. 不能修改被装饰函数的调用方式

装饰器为什么会有这两个原则呐?因为如果你写的这个程序在生产环境下已经运行了,如果修改别人的源代码或者修改别人的调用方式,那么出了问题,后果可想而知,所以我们要牢记上面两个原则。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def logging():
    print("logging...")
 
#正确写法,没有修改源码
def test1():
    pass
 
#错误写法,不能修改源码
def test1():
    pass
    logging()
 
# 调用方式,也不能被修改
test1()

三、实现装饰器知识储备

  1. 函数即"变量"
  2. 高阶函数
  3. 嵌套函数

最终: 高阶函数+嵌套函数 => 装饰器

四、函数即变量

1、python的内存机制

1
2
3
4
5
#变量
= 1
#函数
def test():
    pass

以上一个变量一个函数在内存中的表现形式如下图:

  在python解释器中,有一个概念叫做引用基数,那什么叫引用基数呐,就是比方说,x=1,它会先在内存当中把1这个值试试在在的存放下来,这个x其实就是1的门牌号,也是对1的一次引用。python什么时候把这个1这个屋子清空呐?它会等到1所对应的门牌号都没有了,就会把1这里面的东西给清掉,这个也是python的内存回收机制,就是靠这种方式回收的。

2、del清理

那我们用什么清理呐?用del去清理门牌号,就是对1的值引用的变量,del  x就表示清理掉1对应的x的门派号。如果x没有被del,则x永远不还被删除,除非程序结束了,不然永远不会被删除。del删除的不是1,只是把门牌号x删除了,只是定期刷新时,发现1没有被其他门牌号引用了,才会被清掉。

3、函数在内存的表现形式

我们先通过三个例子来解释一下:

①bar函数在foo函数之后定义

1
2
3
4
5
6
7
8
9
10
11
12
13
#bar函数在foo函数之后定义
def foo():
    print("in the foo")
    bar()
 
def bar():
    print("in the bar")
 
foo()
 
#输出
in the foo
in the bar

②bar函数是在foo函数之前定义

1
2
3
4
5
6
7
8
9
10
11
12
13
# bar函数是在foo函数之前定义
def bar():
    print("in the bar")
 
def foo():
    print("in the foo")
    bar()
 
foo()
 
#输出
in the foo
in the bar

显然,两种写法效果是一样的,那我们来看看第三种情况。

③bar函数在foo函数调用之后声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# bar函数在foo函数调用之后声明
def foo():
    print("in the foo")
    bar()
 
foo()
 
def bar():
    print("in the bar")
 
#输出
Traceback (most recent call last):
in the foo
  File "D:/PycharmProjects/pyhomework/day4/装饰器/函数即变量.py", line 31in <module>
    foo()
  File "D:/PycharmProjects/pyhomework/day4/装饰器/函数即变量.py", line 29in foo
    bar()
NameError: name 'bar' is not defined  #bar函数没有定义

为啥呢?bar函数我不是定义了吗?下面我们就用一个图来解释一下。

从图中不难看出第三种错误是因为在执行foo函数时,当调用bar函数时,bar还函数还定义,所以报错。

五、高阶函数

实现高阶函数有两个条件:

  1. 把一个函数名当做实参传给另外一个函数
  2. 返回值中包含函数名

1、把一个函数名当做实参传给另外一个函数

作用:在不修改被装饰函数源代码的情况下为其添加功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def bar():
    time.sleep(3)
    print("in the bar")
 
def test1(func):
    print(func)
    start_time = time.time()
    func()
    stop_time = time.time()
    print("the func run the is %s"%(stop_time-start_time))
#没有修改bar的代码
test1(bar)  #把bar函数名当做实参传到test1中
 
#输出
<function bar at 0x0000000000A7D378>  #bar函数的内存地址
in the bar
the func run the is 2.9912972450256348

2、返回值中包括函数名

作用:不修改函数调用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import  time
 
def bar():
    time.sleep(3)
    print("in the bar")
 
def test2(func):
    print(func)
    return func   #返回函数的内存地址
 
#调用test2函数
bar = test2(bar) 
bar()  #没有bar函数改变调用方式
 
#输出
<function bar at 0x0000000000B6D378>  #打印bar函数的内存地址
in the bar

函数和常用模块【day05】:装饰器前奏(一)的更多相关文章

  1. 小白的Python之路 day4 装饰器前奏

    装饰器前奏: 一.定义: 1.装饰器本质是函数,语法都是用def去定义的 (函数的目的:他需要完成特定的功能) 2.装饰器的功能:就是装饰其他函数(就是为其他函数添加附加功能) 二.原则: 1. 不能 ...

  2. 探究functools模块wraps装饰器的用途

    <A Byte of Python>17.8节讲decorator的时候,用到了functools模块中的一个装饰器:wraps.因为之前没有接触过这个装饰器,所以特地研究了一下. 何谓“ ...

  3. python进阶04 装饰器、描述器、常用内置装饰器

    python进阶04 装饰器.描述器.常用内置装饰器 一.装饰器 作用:能够给现有的函数增加功能 如何给一个现有的函数增加执行计数的功能 首先用类来添加新功能 def fun(): #首先我们定义一个 ...

  4. 为什么 Python 没有函数重载?如何用装饰器实现函数重载?

    英文:https://arpitbhayani.me/blogs/function-overloading 作者:arprit 译者:豌豆花下猫("Python猫"公众号作者) 声 ...

  5. Python初学者第二十三天 函数进阶(2)装饰器

    装饰器: 需求----> 写一个功能,测试其他同事函数的调用效率. 第一版:功能版 import time def func(): time.sleep(0.2) print('非常复杂') d ...

  6. python函数知识七 闭包、装饰器一(入门)、装饰器二(进阶)

    21.闭包 闭包:在嵌套函数内,使用非全局变量(且不使用本层变量) 闭包的作用:1.保证数据的安全性(纯洁度).2.装饰器使用 .__closure__判断是否是闭包 def func(): a = ...

  7. 函数和常用模块【day05】:装饰器高潮(三)

    本节内容 1.概述 2.装饰器定义 3.装饰器定义 4.带参数的生成器 一.概述 我们之前介绍了大幅片的内容,感觉跟装饰器半毛钱关系都没有,其实不然,我们分别详细阐述了高阶函数和内置函数,下面我们就来 ...

  8. Day05:装饰器,三元表达式,函数的递归,匿名/内置函数,迭代器,模块,开发目录

    上节课复习:1.函数的对象    函数可以被当作数据取处理2.函数嵌套    嵌套调用:在调用一个函数时,函数体代码又调用了其他函数    嵌套定义:在一个函数内部又定义了另一个函数 def foo( ...

  9. python函数与模块(装饰器,文件处理,迭代器等)

    os模块 os.system('命令') 利用python调用系统命令,命令可以是以列表或者元组内的元素形式* res import os res=os.system('ipconfig') prin ...

随机推荐

  1. C++学习之从C到C++

    头文件的包含 包含头文件可以不加.h结尾,如iostream,一些常用的头文件在引用时可以不加.h后缀,并在开头增加c,如: #include <cstdio> #include < ...

  2. 在 JS 对象中使用 . 和 [] 操作属性的区别

    在 JS 对象中,调用属性一般有两种方法--点和中括号的方法. 例如 使用点方法 var obj = { name: "cedric" } console.log(obj.name ...

  3. [SHOI2015]聚变反应炉[树dp、贪心]

    题意 给定一棵 \(n\) 个点的树,每个点有一个启动能量 \(d\) 和传递能量 \(c\) ,如果一个点被启动了,就会向和他直接相连的点发送 \(c\) 的能量,初始所有节点能量为0,问最少多少能 ...

  4. JVM源码---教你傻瓜式编译openjdk7(JAVA虚拟机爱好者必看)

    LZ经过一个星期断断续续的研究,终于成功的搞定了JDK的成功编译与调试.尽管网络上的教程也有不少,包括源码中也有自带的编译步骤说明,但真正自己动手的话,还是会遇到不少意料之外的错误. 为了方便各位猿友 ...

  5. From today 2019.02.27

    HIT开设软件构造课程,需要在博客上分享记录学习体验,感觉还是挺好的. 以后会不定期更新一些关于学下java的笔记和实验相关的内容.

  6. 简言MVC

    什么是MVC? MVC是一种代码的组织结构,在一个工程项目中,将代码的数据处理,逻辑单元和交互部分分离开来达到一种低耦合的效果,便于工程的修改.MVC中M代表Model,V代表View,C代表Cont ...

  7. 《Linux内核设计与实现》Chapter 18 读书笔记

    <Linux内核设计与实现>Chapter 18 读书笔记 一.准备开始 一个bug 一个藏匿bug的内核版本 知道这个bug最早出现在哪个内核版本中. 相关内核代码的知识和运气 想要成功 ...

  8. Linux内核分析第一周总结

    冯诺依曼体系结构 储存程序计算机工作模型 硬件 程序员 CPU当作for循环: IP: 16位计算机:IP 32位计算机:eIP 64位计算机:rIP X86汇编基础 X86的CPU寄存器 X86的C ...

  9. 课堂讨论 alpha版最后总结

    议时间:组队开发最后总结会议   星期一   下午4:30-5:30 会议地点:学院楼自习室 到会人员:唐野野 胡潘华 王永伟 魏孟 会议概要: 1.展示最后开发成果: 2.交流开发过程心得体会: 会 ...

  10. Apache DBUtils框架 结果处理器

    package com.itheima.dbutil; import java.util.List; import java.util.Map; import org.apache.commons.d ...