补充:

  callable 代表可调用的,加括号可以执行。(函数或者类)

  import this  查看python之禅

一。闭包函数

  所谓闭包函数,就是定义在函数内部的函数,也就是函数定义的嵌套。而在其内部函数中可以引用外部函数作用域的名字。

  闭包的直接问题是传参。

  一般的传参方法都是将参数直接传递给函数,函数内部就可以引用,如:

def foo(oop):
print(oop)
foo(123)
#输出结果>>>123

  foo收到参数123后直接打印,而在闭包函数中需要从内函数调用外函数的参数,进行运算,如下:

def outter():
x=1
y=2
def inner():
print(x+y)
return x+y
return inner
res=outter()
res()
#输出结果>>>3

  像内函数inner()就调用了外函数的x与y参数。这里复习一下闭包函数的运行过程。

  当outter被调用时,执行return inner,返回的是inner的内存地址,所以outter()就是outter函数的返回值,所以res就被赋予inner的内存地址,加上()后才能执行print(x+y)。

  res仅仅代表着1与2的值,在运行时并不能对其进行传参,所以一下代码等同于以上代码:

def outter(x,y):
def inner():
print(x+y)
return x+y
return inner
res=outter(1,2)
res()
res=outter(3,4)
res()
#输出结果>>>3 7

  x,y是形参,在创建和传参时就相当于使得x=1,y=2,在外函数中始终有效,所以outter变成了一个有参函数,

  可以对res进行重新赋值改变其return的值。

  对于闭合函数的应用,res可以反复使用而不需要重复对其传参,当参数改变的时侯可以重新对outter进行传参,这种 方便更多的体现在爬虫中(了解):

import requests
def outter(url):
def inner():
res=requests.get(url)#把url网站请求赋值给res
print(res.text)
print(res)
return inner
res=outter('https://i.cnblogs.com/EditPosts.aspx?opt=1')
res()

  res.text代表的就是输出网站所有内容,当不使用以上办法时,需要每次使用时都要对同一函数进行相同的赋值,而闭包函数只需要res即可,对于爬虫来说非常方便。

二。装饰器

  装饰器就是可以给被装饰的对象添加新的功能。

  装饰器满足开放封闭原则,开放就是对外扩展原则,可以对原先的功能进行扩展,封闭:不能修改原来的函数。

  做成一个装饰器必须要满足两个条件:

  1,不改变被装饰对象的源码。

  2,不改变装饰对象的调用方式。

  复习:外函数返回的值是内函数的内存地址,内存地址+()可执行代码,带着这个概念和两个条件,开始接触装饰器:

  补充:

  inport time 模块,time.time()是时间戳,可以返回现在时间距离1970-1-1日的相差秒数(1970.1.1是unix系统诞生的日子)

  time.sheep(3)

  有一个函数,index,需要判断其程序的运行时间,如何使用装饰器对其进行功能的拓展。

  首先用time模块可以对其进行功能上的实现:

import time

def index():
time.sleep(3)
print('我是登录程序') time1=time.time()
index()
time2=time.time()
print(time2-time1)
#输出结果>>>
#我是登录程序
#3.0007030963897705

  然而并没有使用函数进行封装,所以使用函数版:

def get_time():
time1=time.time()
index()
time2=time.time()
print(time2-time1)
get_time()

  get_time函数只能对index函数进行功能拓展,所以并没有实现装饰器功能,调用的时候没有使用原来的调用名index,所以,为了达到这一目的,可以使用闭包函数,将get_time()的内存地址返回给外函数,再将外函数的值传给原函数,就可以使用原函数的名字调用get_time函数了。

def outter():
def get_time():
time1=time.time()
index()
time2=time.time()
print(time2-time1)
return get_time
res=outter()
res()

  这样一个针对index的函数的装饰器差不多构成了,但还是不满足调用原函数实现拓展功能的目标,而且这里不能直接将get_time的内存地址赋给内函数传给原函数,否则执行index=get_time()函数时会将get_time里的函数都执行一遍,给外函数就不会出现这个问题。

  对于上代码中只是针对index做的装饰器,换做其他的函数就不可用,所以要将装饰器中的index()当成参数传入,其形参就定义再外函数中被传入。

def register():
time.sleep()
print('我是注册程序') def outter(func):
def get_time():
time1=time.time()
func()
time2=time.time()
print(time2-time1)
return get_time
res=outter(index)
index=res
index()
register=outter(register)
register()
#输出结果>>>我是登录程序
#3.000358819961548
#我是注册程序
#3.0000927448272705

  这样将函数名代表的内存地址传入内函数中,加上()就可以被执行,将外函数返回的内函数内存地址赋值给原函数名,再加()就可以执行,效果和装饰器一致,所以,outter满足了无参函数的装饰器所有规定。

  既然有无参函数,就有有参函数,当有参函数被传入的时后,其参数不能被内函数接受,所以,要装饰有参函数,必须要将参数以某种形式传入,这里选择了可以接受多余参数的*和** 做为形参。

def print_name(name):
time.sleep()
print('我是%s'%name)
  return 'name' def outter(func):
def get_time(*args,**kwargs):
time1=time.time()
func(*args,**kwargs)
time2=time.time()
print(time2-time1)
return get_time
print_name('lzx')
print_name=outter(print_name)
print_name('lzx')
#输出结果>>>我是lzx
#我是lzx
#3.0001375675201416

  这样的装饰器,有一个小小的问题,当用户需要返回print_name的返回值时,会出现不一样的情况

print(print_name('lzx'))
print_name=outter(print_name)
print_name('lzx')
print(print_name('lzx'))
#输出结果>>>我是lzx
#name
#我是lzx
#3.0016050338745117
#我是lzx
#3.0001797676086426
#None

  在装饰器之前打印次函数的返回值时时name原返回值,但是当装饰之后只会返回none,那返回值去哪了返回的是谁的返回值呢,这里需要短暂的分析

  当程序运行时,编译好outter函数后,再将其返回的get_time内存地址返回给print_name也就是原函数,再运行原函数时实际就是运行内函数get_time所以再执行第三步时其实是返回的get_time的返回值,而其中真正的返回值只要函数func拥有,所以为了实现完美装饰器功能,必须将get_name的函数返回值与原函数的返回值一致。

def register():
time.sleep()
print('我是注册程序')
def print_name(name):
time.sleep()
print('我是%s'%name)
return 'name' def outter(func):
def get_time(*args,**kwargs):
time1=time.time()
res=func(*args,**kwargs)
time2=time.time()
print(time2-time1)
return res
return get_time
# print(print_name('lzx'))
print_name=outter(print_name)
# print_name('lzx')
print(print_name('lzx'))
#输出结果>>>我是lzx
#3.0002002716064453
#name

  如上便是一个完整功能的装饰器。

  装饰器语法糖

  在每次需要调用装饰器时,都要执行原函数=装饰器(原函数)这样的操作,很麻烦,所以可以使用装饰器语法糖

def outter(func):
def get_time(*args,**kwargs):
time1=time.time()
res=func(*args,**kwargs)
time2=time.time()
print(time2-time1)
return res
return get_time @outter
def register():
time.sleep(3)
print('我是注册程序') register()
#输出结果>>>我是注册程序
#3.000058889389038

  @outter对于register相当于register=outter(register),将紧挨着的那个对象当作参数赋值给它,和上述语法差不多。

  装饰器模板

def outter(func):
def inner(*args,**kwargs):
print('执行被装饰函数之前 你可以做的操作')
res = func(*args,**kwargs)
print('执行被装饰函数之后 你可以做的操作')
return res
return inner

  这便是装饰器的模板

  有参装饰器

  当装饰器中需要调用额外的参数时,如何将参数传递呢,在内函数中,参数时提供给原函数使用,如果改变,势必要改变原函数,与装饰器原则不符,而外函数的参数是传递原函数,如果增加,在使用语法糖时会报错(参数不足),所以,需要在外函数外再报一个函数:

def outter2(choose):
def outter(func):
def get_time(*args,**kwargs):
if choose==1:
time1=time.time()
res=func(*args,**kwargs)
time2=time.time()
print(time2-time1)
return res
elif choose==2:
return 0
return get_time
return outter @outter2(1)
def register():
time.sleep(3)
print('我是注册程序')
#输出结果>>>我是注册程序
#3.0003597736358643

  语法糖是可以传入参数的,当传如1时会执行语句,传入0 时什么都不执行,这个参数可以传入多个,所有多余参数都可以写入。

  装饰器修复:

  当用户对被装饰后的函数去内存地址和备注时,并不会返回原来的内存地址,而是返回内函数的,所以为了以假乱真,可以使用from functools import wraps,再再外函数里使用@wrap(func)语句就可以返回原来的内存地址及注释

from functools import wraps
def outter2(choose):
def outter(func):
@wraps(func)
def get_time(*args,**kwargs):
if choose==1:
time1=time.time()
res=func(*args,**kwargs)
time2=time.time()
print(time2-time1)
return res
elif choose==2:
return 0
return get_time
return outter

  多个装饰器

  当多个装饰器装饰一个函数时他们的顺序是规定 的

@outter1  # index = outter1(wapper2)
@outter2 # wrapper2 = outter2(wrapper3)
@outter3 # wrapper3 = outter3(最原始的index函数内存地址)
def index():
print('from index')

  其执行顺序是

加载了outter3

加载了outter2

加载了outter1

执行了wrapper1

执行了wrapper2

执行了wrapper3

from index  

  所以它们的执行规则应该是装饰顺序为从下往上,执行顺序为从上往下。

day11_7.11 闭包函数与装饰器的更多相关文章

  1. day11 闭包函数和装饰器

    1.函数不是新知识点 主要是学习函数的用法 在面向对象编程中,一切皆对象,函数也不例外 具体的表现 1.函数可以引用 2.函数可以作为函数的参数 3.函数可以作为函数的返回值 4.可以被存储到容器类型 ...

  2. python基础-闭包函数和装饰器

    闭包函数和装饰器 闭包函数 概念:在函数中(嵌套)定义另一个函数时,内部函数引用了外层函数的名字. 特性 闭包函数必须在函数内部定义 闭包函数可引用外层函数的名字 闭包函数是函数嵌套.函数对象.名称空 ...

  3. Python之函数对象、函数嵌套、名称空间与作用域、闭包函数、装饰器

    目录 一 函数对象 二 函数的嵌套 三 名称空间和作用域 四 闭合函数 五 装饰器 一.函数对象 1.函数是第一类对象 #第一类对象的特性:# 可以被引用 # 可以当做参数传递 # 返回值是函数 # ...

  4. 【Python3的命名空间与作用域,闭包函数,装饰器】

    一.命名空间与作用域 命名空间是名字和对象的映射,就像是字典,key是变量名,value是变量的值 1.命名空间的定义 name='egon' #定义变量 def func(): #定义函数 pass ...

  5. CSIC_716_20191112【闭包函数和装饰器】

    闭包函数 什么是闭包函数:闭包函数是函数嵌套.函数对象.名称空间和作用域的集合体. 闭包函数必须在函数内部定义,闭包函数可以引用外层函数的名字. # _*_ coding: gbk _*_ # @Au ...

  6. Python基础之函数:2、globlal与nonlocal和闭包函数、装饰器、语法糖

    目录 一.global与nonlocal 1.global 2.nonlocal 二.函数名的多种用法 三.闭包函数 1.什么是闭包函数 2.闭包函数需满足的条件 3.闭包函数的作用 4.闭包函数的实 ...

  7. Python--day13(函数嵌套定义,global、nonlocal、闭包函数、装饰器)

    今日主要内容 1.  函数的嵌套定义 2.  global.nonlocal关键字 3.  闭包及闭包的应用场景 4. 装饰器 1.  函数的嵌套定义 概念:在一个函数的内部定义另一个函数 为什么要有 ...

  8. python---基础知识回顾(二)(闭包函数和装饰器)

    一.闭包函数: 闭包函数: 1.在一个外函数中定义了一个内函数 2.内函数里运用了外函数的临时变量,而不是全局变量 3.并且外函数的返回值是内函数的引用.(函数名,内存块地址,函数名指针..) 正确形 ...

  9. Python之闭包函数、装饰器

    1.闭包函数 #作用域关系在函数定义阶段时就已经固定死了,与调用位置无关 # 即:在任意位置调用函数都需要跑到定义函数时寻找作用域关系 # def f1(): # x=1 # def inner(): ...

随机推荐

  1. PageHelper分页(十)

    分页有两种: (1) 物理分页:物理分页依赖的是某一物理实体,这个物理实体就是数据库,比如MySQL数据库提供了limit关键字,程序员只需要编写带有limit关键字的SQL语句,数据库返回的就是分页 ...

  2. MySQL的delete误操作的快速恢复方法

    1. 根据误操作时间定位binlog位置找到数据库的binlog存放位置,当前正在使用的binlog文件里面就有我们要恢复的数据.一般生产环境中的binlog文件都是几百M乃至上G的大小,我们不能逐行 ...

  3. JavaScript DOM 常用操作

    1.理解DOM: DOM(Document Object Model ,文档对象模型)一种独立于语言,用于操作xml,html文档的应用编程接口. 怎么说,我从两个角度理解: 对于JavaScript ...

  4. 本地运行vue项目webpack提示 Compiled successfully

    最近在github下载运行别人的vue项目后,如下图提示编译成功,但项目并没有启动       最开始我以为是端口问题,修改了config-index.js里的port端口,重新运行后依然是上图提示 ...

  5. python小项目(python实现鉴黄)源码

    import sys import os import _io from collections import namedtuple from PIL import Image class Nude( ...

  6. Redhat6.6替换Centos Yum源

    1.删除当前系统自带的yum [root@reddhat6_155_201 ~]# rpm -qa |grep yum yum-rhn-plugin--.el6.noarch yum-utils--. ...

  7. Kubernetes service 三种类型/NodePort端口固定

    Kubernetes service 三种类型 • ClusterIP:默认,分配一个集群内部可以访问的虚拟IP(VIP)• NodePort:在每个Node上分配一个端口作为外部访问入口• Load ...

  8. sysstat工具包之mpstat

    mpstat 1 简介 mpstat是一个实时监控工具,主要报告与CPU相关统计信息,信息存放在/proc/stat文件中: 在多核心cpu系统中,不仅可以查看cpu平均信息,还可以查看指定cpu信息 ...

  9. PyTestReport 自动化报告

    安装 pip install PyTestReport pytest框架执行命令 pytest.main(["-s", "test_login.py", &qu ...

  10. vs扩展和更新插件的开发

    一.调试 以 MinimalisticView.vsix (https://github.com/poma/MinimalisticView) 为例. 正如 | Marketplace 上介绍的,这个 ...