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

时间:2022-01-02 03:04:26

一.闭包函数:

闭包函数:

1.在一个外函数中定义了一个内函数

2.内函数里运用了外函数的临时变量,而不是全局变量

3.并且外函数的返回值是内函数的引用。(函数名,内存块地址,函数名指针..)

正确形式:

def outer():
name = "dasfa"
def inner():
print("inner func exec,get outer func name",name)
return inner func = outer()
func() #执行内联中的函数"inner func exec,get outer func name dasfa"

案例一:内联函数inner使用的是外部outer函数中的数据

>>> def outer():
... age =
... print(id(age))
... def inner():
... print("age",age)
... print(id(age))
... return inner
...
>>> func = outer() >>> func()
age

案例二:是否可以修改outer中的数据:

>>> def outer():
... age =
... print(id(age))
... def inner():
... age =
... print(id(age))
... return inner
...
>>> func = outer() >>> func()

就同python---基础知识回顾(一)所说的传参一样,要想修改,那就需要将其中的变量设置为可变类型(列表等)

使用闭包的好处:含有自己的变量,不与全局变量相冲突。可以不用传参。

闭包的__closure__变量

闭包都有__closure__属性,会返回外部作用域中的变量信息。

>>> def outer():
... age =
... print(id(age))
... def inner():
... print(id(age))
... print(age)
... return inner
...
>>> func = outer() >>> print(func.__closure__)
(<cell at 0x0000000000CF8DC8: int object at 0x0000000077FB5440>,)  #返回元组,若是有多个变量,都会显示在这里面,我们都可以通过索引获取
>>> print(func.__closure__[])    #获取地址
<cell at 0x0000000000CF8DC8: int object at 0x0000000077FB5440>
>>> print(func.__closure__[].cell_contents)  #获取值

注意:若是引用的是全局变量,获取inner函数中将外部outer函数中的变量进行覆盖后,那么func.__closure__会为空

闭包的简单使用:

from urllib.request import urlopen

def outer(url):
def get():
return urlopen(url).read()
return get info = outer("https://www.baidu.com")
print(info()) b'<html>\r\n<head>\r\n\t<script>\r\n\t\tlocation.replace(location.href.replace("
https://","http://"));\r\n\t</script>\r\n</head>\r\n<body>\r\n\t<noscript><meta
http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>\r\n</body
>\r\n</html>'

二.装饰器函数:

python装饰器:(开放封闭原则)

python 装饰器

就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。

开放封闭原则:虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改

(封闭:已实现的功能代码块,开放:对扩展开发)

装饰器简单实现:

def check_login(func):
def inner():
#验证1
#验证2
#...
return func()
return inner @check_login
def f1():
print("f1") @check_login
def f2():
print("f2") @check_login
def f3():
print("f3")

装饰器:外部函数参数为:被装饰函数名,内部函数返回装饰函数名。

特点:1.不修改被装饰函数的调用方式 2.不修改被装饰函数的源代码。

其执行顺序:@函数名是python中的一种语法形式,其内部会执行下面操作:

.执行check_login函数,并且将@check_login下面的函数作为参数,传递进去。等价于check_login(f1)
在内部会执行
    def inner():
#验证1
#验证2
#...
return func() #func是参数,相当于传入的函数名
return inner     #返回的inner,inner代表的是函数名,不会去执行,会将这个函数传递到另外一个函数中
2.将执行完的check_login函数返回值给@check_login下面修饰的函数的函数名:相当于对该函数进行了重新赋值(这个新的函数是经过修改验证后的函数)
新f1 = inner #inner中添加了验证代码,然后执行了原来f1的逻辑代码
3.执行新f1。即完成了验证功能,有执行了原来F1的内容。并将其原来函数的返回值返回给业务调用

补充:多个装饰器同时修饰时的调用顺序:

>>> def check_1(func):
... def inner():
... print("check_1")
... func()
... return inner
...
>>> def check_2(func):
... def inner():
... print("check_2")
... func()
... return inner
...
>>> @check_1    index = check_1(check_2(index)) #后
... @check_2    index = check_2(index) #先,然后将这个新的函数作为参数传递
... def index():
... print("进入首页")
...
>>> index()
check_1
check_2
进入首页
... @check_2    index = check_2(index)  #先,然后将这个新的函数作为参数传递
... def index():
... print("进入首页") index = def inner():
print("check_2")
print("进入首页")

@check_2

@check_1

最新的index函数是上面被check_2和check_1修饰过的函数.

check_1
check_2
进入首页

执行结果

有参装饰器:

外部函数是用来接收被装饰函数的地址

内联函数是用来接收参数(一般是与被修饰函数一致,因为inner函数中调用了被修饰函数,需要对其进行传参)

def check_login(func):
def inner(*args,**kwargs):
return func()
return inner

与被修饰函数不一致情况

接收一个参数
def check_func(func):
def inner(arg1,arg2):
#验证
if 正确:
return func(arg1,arg2)
return inner @check_login
def index(arg1,arg2):
print("欢迎来到首页")

接收两个参数

def check_func(func):
def inner(*args,**kwargs):
#验证
if 正确:
return func(*args,**kwargs)
return inner @check_login
def index(*args,**kwargs):
print("欢迎来到首页")

接收多个参数

更强大装饰器:

def Before(request, kargs):
print('before') def After(request, kargs):
print('after') def Filter(before_func, after_func):
def outer(main_func):
def wrapper(request, kargs):
before_result = before_func(request, kargs)
if (before_result != None):
return before_result main_result = main_func(request, kargs)
if (main_result != None):
return main_result after_result = after_func(request, kargs)
if (after_result != None):
return after_result
return wrapper
return outer @Filter(Before, After)  #注意,这里是先执行该外层函数然后返回outer函数名给@符号,进行处理。
def Index(request, kargs):
print('index') Index("aa","bb")

类装饰器:

装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。

class Foo(object):
def __init__(self, func):
self._func = func def __call__(self):
print('class decorator runing')
self._func()
print('class decorator ending') @Foo  # bar = Foo(bar) 传入到__init__函数中 , 返回时使用__call__
def bar():
print('bar') bar()  # Foo(bar)() # 结果
# class decorator runing
# bar
# class decorator ending

functools.wraps

虽然使用装饰器极大的复用了代码,但是他有一个缺点,就是原函数的元信息不见了,比如__doc__,__name__,参数列表:

def check_login(func):
def inner():
'''验证信息'''
print("验证")
func()
return inner @check_login
def f1():
'''首页信息'''
print("f1 exec") f1()
print(f1.__doc__)    #“验证信息”,若是inner中也没有__doc__信息,那么这里为空
print(f1.__name__)    #“inner”

这可不是我们想要的信息。解决方案是:functool.wraps

functool.wraps本身也是一个装饰器,他将原函数的元信息拷贝到装饰器函数中,这使得装饰器函数也有和原函数一样的元信息了。

from functools import wraps

def check_login(func):
@wraps(func)
def inner():
'''验证信息'''
print("验证")
func()
return inner @check_login
def f1():
'''首页信息'''
print("f1 exec") f1()
print(f1.__doc__) #"首页信息"
print(f1.__name__) #"f1"

常用的内置装饰器:

@staticmathod,@classmethod,@property

python---基础知识回顾(二)(闭包函数和装饰器)的更多相关文章

  1. python基础知识7——迭代器,生成器,装饰器

    迭代器 1.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器 ...

  2. python爬虫主要就是五个模块:爬虫启动入口模块,URL管理器存放已经爬虫的URL和待爬虫URL列表,html下载器,html解析器,html输出器 同时可以掌握到urllib2的使用、bs4(BeautifulSoup)页面解析器、re正则表达式、urlparse、python基础知识回顾(set集合操作)等相关内容。

    本次python爬虫百步百科,里面详细分析了爬虫的步骤,对每一步代码都有详细的注释说明,可通过本案例掌握python爬虫的特点: 1.爬虫调度入口(crawler_main.py) # coding: ...

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

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

  4. day11 闭包函数和装饰器

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

  5. python基础知识(二)

    以下内容,作为python基础知识的补充,主要涉及基础数据类型的创建及特性,以及新数据类型Bytes类型的引入介绍

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

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

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

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

  8. day11&lowbar;7&period;11 闭包函数与装饰器

    补充: callable 代表可调用的,加括号可以执行.(函数或者类) import this  查看python之禅 一.闭包函数 所谓闭包函数,就是定义在函数内部的函数,也就是函数定义的嵌套.而在 ...

  9. Python学习第四十天函数的装饰器用法

    在软件开发的过程中,要遵循软件的一些原则封装的,不改变原有的代码的基础增加一些需求,python提供了装饰器来扩展函数功能,下面说说函数装饰器用法 def debug(func):      def ...

  10. CSIC&lowbar;716&lowbar;20191112【闭包函数和装饰器】

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

随机推荐

  1. Struts2 源码分析——调结者&lpar;Dispatcher&rpar;之准备工作

    章节简言 上一章笔者讲到关于struts2过滤器(Filter)的知识.让我们了解到StrutsPrepareFilter和StrutsExecuteFilter的作用.特别是StrutsPrepar ...

  2. 【CodeForces 577C】Vasya and Petya’s Game

    链接 某个数x属于[1,n],至少询问哪些数“x是否是它的倍数”才能判断x.找出所有质因数和质因数的幂即可. #include<cstdio> #include<algorithm& ...

  3. iOS逆传值的三种方式

    1.代理 2.block 2.通知中心

  4. js isnull 赋值方法

    <script>var b = 'test';var a = b || {};alert(a)</script> 结果:test <script>var b;var ...

  5. ios上传应用后,审核流程完成前(reveiw)修改了程序内容,如何上传替换

    其实挺简单,只需要更改下version和build版本 看图说话就可以.我的程序之前版的版本设置 修改bug之后的设置: 然后重新打包就好了,提示打包成功后,在itunesconnect查看发现 选中 ...

  6. 配置managed server

    managed server往往是部署应用程序的server,所以最好在weblgoic上配置上managed server,不要把应用程序直接部署到admin server上. 一.受管服务器的创建 ...

  7. log4net使用特定的解释

    说明:该程序演示如何使用log4net记录日志信息. log4net它是-known开源组件的日志记录功能.使用log4net可以很容易地将信息记录到文件.控制台.Windows事件日志和数据库(含有 ...

  8. 讲解——Trie树(字典树)

          Trie树(字典树) 一.引入 字典是干啥的?查找字的. 字典树自然也是起查找作用的.查找的是啥?单词. 看以下几个题: 1.给出n个单词和m个询问,每次询问一个单词,回答这个单词是否在单 ...

  9. js 倒计时(服务器时间同步)

    首先说一下,为什么要服务器时间同步, 因为服务器时间和本地电脑时间存在一定的时间差.有些对时效性要求非常高的应用,例如时时彩开奖,是不能容忍这种时间差存在的. 方案1:每次倒计时去服务端请求时间 // ...

  10. C&plus;&plus;中多态中构造函数与析构函数的调用

    做个实验,看一下成员变量的构造析构,父类子类的构造析构,以及虚函数对调用的影响. #include <iostream> using namespace std; class Member ...