装饰器

函数名的应用

  直接打印函数名得到的是函数的内存地址。

def func1():
print(666)
print(func1)

  函数名可以赋值运算。

def func1():
print(666) f1 = func1
f1()

  函数名可以作为函数的参数。

def func1():
print(666)

def func2(x):
x()
print(555) func2(func1)

  函数名可以作为容器类数据类型的元素。

def func1():
print(666) def func2():
print(222) def func3():
print(111) def func4():
print(777) l1 = [func1, func2, func3, func4]
for i in l1:
i()

def func1():
print(666) def func2():
print(222) def func3():
print(111) def func4():
print(777) dic1 = {
1: func1,
2: func2,
3: func3,
4: func4,
}
dic1[1]()

  函数名可以当做函数的返回值。  

def func1():
print(666) def func2(x):
print(222)
return x ret = func2(func1)
ret()

闭包

  内层函数对外层函数的非全局引用就叫闭包。

  判断是不是闭包,函数名:__closure__ 

  返回None则不是闭包;返回cell就是闭包。 

def func1():
name = '老男孩' def inner():
print(name)、
inner()
print(inner.__closure__) func1()

 

  global声明了一个全局变量,此时name为全局变量,所以就不时闭包。

def func1():
global name # 声明全局变量name
name = '老男孩' def inner():
print(name) inner()
print(inner.__closure__) func1()

def func1(x):
def inner():
print(x)
inner()
print(inner.__closure__) name = '老男孩'
func1(name)

def func():
def func1():
name = "老男孩" def func2():
nonlocal name    # 对父级变量改变
name = "alex" def func3():
global name    # 声明一个全局变量
name = "太白"
name = "日天" func1()
print(name)
func2()
print(name)
func3()
print(name) func()
print(name)

  当代码从上到下加载到func()时,代码开始执行。跳到func函数体里边,加载函数func1、func2、func3,加载到func1()时执行函数func1,执行完后打印name,print(name)在函数func的作用域中,所以此时name的值为'日天';加载到fun2()时,执行函数func2,此时修改了函数func2的父作用域中的name的值为'alex',也就是函数func中name的值,打印name时,找的是func作用域中的name,此时name的值为'alex';加载到func3()时,开始执行func3,此时修改了全局变量name的值为'太白',完了打印name时,此时print(name)所在的是func的作用域,由于func2修改了func作用域中name的值为'alex',所以此时name的值依旧为'alex';现在来到了最后一行代码处,此时name找的是全局作用域中name的值,由于函数func3修改了全局作用域中name的值为'太白',所以最后输出为太白。

  执行顺序如下:

闭包的作用

  当执行一个函数时,如果解释器判断此函数内部闭包存在,这样Python就存在一个机制,闭包所在的临时名称空间不会随着函数的执行完毕而消失。

from urllib.request import urlopen

def index():
url = "https://user.qzone.qq.com/569894146/infocenter" def get():
return urlopen(url).read()
return get kongjian = index()
content = kongjian() print(content)

装饰器

函数方式

  使用函数的方式,来为另外一个函数添加功能。

import time

def login():
time.sleep(0.3)
print('洗洗更健康...') def timmer():
start_time = time.time()
login()
end_time = time.time()
print('此函数的执行时间%s' % (end_time - start_time)) timmer()

改变了原来执行函数的方式

  将函数作为参数传递到装饰器函数中,实现简单的通用装饰函数。

def login():
time.sleep(0.3)
print('洗洗更健康...') def register():
time.sleep(0.4)
print('洗洗更健康22222...') def timmer(f):
start_time = time.time()
f()
end_time = time.time()
print('此函数的执行时间%s' % (end_time - start_time)) timmer(login)
timmer(register)

初级装饰器

def login():
time.sleep(0.3)
print('洗洗更健康...') def timmer(f):
def inner():
start_time = time.time()
f()
end_time = time.time()
print('此函数的执行时间%s' % (end_time - start_time)) return inner login = timmer(login)
login()

  函数执行顺序:

    加载函数login、函数timmer,然后加载login = timmer(login),这一步执行了函数timmer,并且将login函数作为参数传给了函数timmer,然后加载函数dinner,将inner return出去,此时的login接收的是函数timmer的返回值,也就是login此时已经是函数inner了,最后login加括号执行的是函数inner。

  这里边的几个坑就是赋值,不要被login = timmer(login)赋值所干扰了。

简单版装饰器 语法糖

  下边这个是简单版的装饰器,我们一起来看下它的执行顺序。

def timmer(f):  # f = login函数名
def inner():
start_time = time.time()
f() # login()
end_time = time.time()
print('此函数的执行时间%s' % (end_time - start_time)) return inner @timmer # login = timmer(login) # inner 此login是新变量
def login():
time.sleep(0.3)
print('洗洗更健康...') login() @timmer # register = timmer(register)
def register():
time.sleep(0.2)
print('洗洗更健康22...') login() # inner()

  执行顺序:

  下边的函数register的执行顺序是在函数login执行完以后开始执行的,调用顺序与函数login是一致的。但是它的加载是在login函数加载完成以后加载的。

被装饰的函数带参数的装饰器

  下边我们来看下带参数的装饰器是如何进行参数的传递和执行的:

def timmer(f):  # f = login函数名
def inner(*args, **kwargs): # args (2, 3)
start_time = time.time()
f(*args, **kwargs) # login() *(2, 3) 2,3
end_time = time.time()
print('此函数的执行时间%s' % (end_time - start_time)) return inner @timmer # login = timmer(login) # inner 此login是新变量
def login(a, b):
print(a, b)
time.sleep(0.3)
print('洗洗更健康...') login(2, 3) # inner(2,3) @timmer # register = timmer(register)
def register(a):
time.sleep(0.2)
print('洗洗更健康22...') register(1) # inner(1)

  执行顺序:

  上图中,蓝色的为函数的传递过程;绿色的为参数的传递过程。下边的register函数的执行与参数的传递过程一致。

函数带返回值的装饰器(万能装饰器)

  下边是一个功能完善的装饰器,我们一起来看下他的参数传递以及执行过程:

def timmer(f):  # f = login函数名
def inner(*args, **kwargs): # args (2, 3)
start_time = time.time()
ret = f(*args, **kwargs) # login() *(2, 3) 2,3
end_time = time.time()
print('此函数的执行时间%s' % (end_time - start_time))
return ret return inner @timmer # login = timmer(login) # inner 此login是新变量
def login(a, b):
print(a, b)
time.sleep(0.3)
print('洗洗更健康...')
return 666 print(login(2, 3)) # inner(2,3)

  装饰器的执行顺序、参数、返回值的传递过程:

  其中绿色的为参数的传递过程,紫色的为返回值传递的过程。

装饰器模板

  下边的是满满的干货,你可以不知道执行顺序,但是你要知道怎么用,没错儿,背过他就行了。

def wrapper(f):
def inner(*args, **kwargs):
'''执行被装饰函数之前的操作'''
ret = f(*args, **kwargs)
"""执行被装饰函数之后的操作"""
return ret return inner

装饰器的作用

    在不改变原函数的基础场,为原函数增加一些功能,log、登录注册等。

python_函数名的应用、闭包、装饰器的更多相关文章

  1. day20 Python 高阶函数,函数,嵌套,闭包 装饰器

    高阶函数定义 1.函数接收的参数是一个函数名 2.函数的返回值是一个函数名 3.满足上述条件任意一个都可以称之为高阶函数 一.函数的接收参数是一个函数名 import time def foo(): ...

  2. python函数闭包-装饰器-03

    可调用对象 callable()  # 可调用的(这个东西加括号可以执行特定的功能,类和函数) 可调用对象即  callable(对象)  返回为  True  的对象 x = 1 print(cal ...

  3. 闭包&装饰器详解

    闭包 先不着急看闭包的定义,让我们从一段示例代码开始.如果将上一个示例稍微修改下: >>> def outer(): ... x = 1 ... def inner(): ... p ...

  4. 【Python】 闭包&装饰器

    python中的函数本身就是对象,所以可以作为参数拿来传递.同时其允许函数的层级嵌套定义,使得灵活性大大增加. 闭包 闭包的定义:将函数的语句块与其运行所需要的环境打包到一起,得到的就是闭包对象.比如 ...

  5. Python闭包装饰器笔记

    Python三大器有迭代器,生成器,装饰器,这三个中使用最多,最重要的就是装饰器.本篇将重要从函数嵌套开始讲起,从而引入闭包,装饰器的各种用法等. python中的一切都是一个对象(函数也是) 1.首 ...

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

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

  7. Python 进阶_闭包 & 装饰器

    目录 目录 闭包 函数的实质和属性 闭包有什么好处 小结 装饰器 更加深入的看看装饰器的执行过程 带参数的装饰器 装饰器的叠加 小结 装饰器能解决什么问题 小结 闭包 Closure: 如果内层函数引 ...

  8. python基础语法_9-1闭包 装饰器补充

    1.闭包的概念 closure:内部函数中对enclosing作用域的变量进行引用,外部函数返回内部函数名   2.函数实质与属性 函数是一个对象:在内存中有一个存储空间 函数执行完成后内部变量回收: ...

  9. python高级-闭包-装饰器

    闭包内容: 匿名函数:能够完成简单的功能,传递这个函数的引用,只有功能 普通函数:能够完成复杂的功能,传递这个函数的引用,只有功能 闭包:能够完成较为复杂的功能,传递这个闭包中的函数以及数据,因此传递 ...

随机推荐

  1. 在Unity中对Lua进行调试

    前言 接我之前的文章,讲到使用IntelliJ IDEA(做为Lua的编辑器)+EmmlyLua(插件),当然EmmlyLua也提供调试功能的. Lua代码提示和方法跳转 在Lua中提示UnityEn ...

  2. 开发nginx启动脚本及开机自启管理(case)

    往往我们在工作中需要自行写一些脚本来管理服务,一旦服务异常或宕机等问题,脚本无法自行管理,当然我们可以写定时任务或将需要管理的脚本加入自启等方法来避免这种尴尬的事情,case适用与写启动脚本,下面给大 ...

  3. May 25. 2018 Week 21st Friday

    Nothing for nothing. 不费力气,就一无所得. These days I am busy in compiling a lightweight communication libra ...

  4. Java多线程(二)关于多线程的CPU密集型和IO密集型这件事

    点我跳过黑哥的卑鄙广告行为,进入正文. Java多线程系列更新中~ 正式篇: Java多线程(一) 什么是线程 Java多线程(二)关于多线程的CPU密集型和IO密集型这件事 Java多线程(三)如何 ...

  5. 《生命》第二集:Reptiles and Amphibians (爬行和两栖动物)

    第二集也是一个个动物的片段,不过集中在爬行和两栖类动物上. 印度尼西亚的瀑布蟾蜍进化出神器强有力的脚,能够抓牢很多物体,是逃生的手段,同一环境下,卵石蟾蜍,能够缩紧全身肌肉,眼山坡下滑,是另一种逃生是 ...

  6. Linux之命令进阶

    Linux系统的启动过程 1.开机自检 BIOS2.MBR引导3.GRUB菜单4.加载内核5.运行init进程6.从/etc/inittab读取运行级别7.根据/etc/rc.sysinit 初始化系 ...

  7. 提升SQLite数据插入效率低、速度慢的方法

    前言 SQLite数据库由于其简单.灵活.轻量.开源,已经被越来越多的被应用到中小型应用中.甚至有人说,SQLite完全可以用来取代c语言中的文件读写操作.因此我最近编写有关遥感数据处理的程序的时候, ...

  8. Android中实现短信发送的一种方式

    SendSmsActivity.java: package com.test.smsmangerdemo.sendsmsactivity; import android.support.v7.app. ...

  9. Rancher学习笔记----在UI界面添加主机页面无法正常显示

    今天在学习rancher添加主机的时候,遇到了一个小问题,但是困扰老娘一上午 问题描述:在点击添加主机的时候,页面有跳转,但是页面显示为空,没有任何可选项.如下正常界面: 解决办法是:请换个浏览器

  10. AI 概率图模型

    概率图模型(Probabilistic Graphical Model) 有向图模型 信念网络 贝叶斯网络 无向模型 马尔科夫随机场 马尔科夫网络