Python装饰器的详细介绍

装饰器本身是一个Python函数,他可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个额外的对象。

先来了解几个定义:

1,函数

在python中,函数通过def关键字、函数名和可选的参数列表定义。通过return关键字返回值。我们举例来说明如何定义和调用一个简单的函数:

 

立即学习“Python免费学习笔记(深入)”;

#coding:UTF8def foo():     return 1print foo()1

登录后复制

方法体(当然多行也是一样的)是必须的,通过缩进来表示,在方法名的后面加上双括号()就能够调用函数

2,作用域

在Python中,函数会创建一个新的作用域. Python开发者可能会说函数有自己的命名空间.这就意味着在函数内部碰到一个变量的时候函数会优先在自己的命名空间里寻找.来简单举例说明本地作用域与全局作用域

 

立即学习“Python免费学习笔记(深入)”;

#coding:UTF8a_string = "This is a global variable"def foo():     print locals()print globals() # doctest: +ELLIPSISfoo()  #2{'foo': , ...., 'a_string': 'This is a global variable',...}{}

登录后复制

 

立即学习“Python免费学习笔记(深入)”;

  内置的函数globals返回一个包含所有Python解释器知道的变量名称的字段(省略一部分)在#2调用了函数foo 把函数背部本地作用域里面的内容打印出来.可以看到,函数foo有自己的独立的命名空间,即使暂时命名空间啥也没有.

3,变量解析规则

当然并不是说在函数里就不能访问外面的全局变量.在Python的作用域规则里,创建变量一定会在当前作用域里创建一个变量,但访问或者修改变量是会现在当前作用域查找变量,没有找到匹配变量会依次向上在闭合的作用域里进行查找.so 如修改函数foo的是实现打印全局的作用域的变量也是可以的

#coding:UTF8a_string = "This is a global variable"def foo():     print a_string   #1foo()This is a global variable

登录后复制

在#1处,Python解释器会尝试查找变量a_string,当然在函数的本地作用域是找不到,so接着会在上层的作用域去查找
但在另外一方面,假如在函数的内部给全局变量赋值,结果会不一样 

 

立即学习“Python免费学习笔记(深入)”;

#coding:UTF8a_string = "This is a global variable"def foo():    a_string='Test'  #1    print locals()    foo(){'a_string': 'Test'}print a_string  #2This is a global variable

登录后复制

 

立即学习“Python免费学习笔记(深入)”;

  全局变量能够被访问到(如果是可变数据类型(像list,dict这些),甚至能够被更改),但赋值就不行了,在函数内部的#1,实际上新创建了一个局部变量,隐藏全局作用域中的同名变量,可以通过打印出全局命名空间中的内容得出这个结论.也可以在#2处打印出来的a_string没有改变

4,变量生存周期

值得注意的是:变量不仅是生存在一个个的命名空间里,都有自己的生存周期,如下:

 

立即学习“Python免费学习笔记(深入)”;

#coding:UTF8def foo():     x = 1foo()print x # 1NameError: name 'x' is not defined

登录后复制

 

立即学习“Python免费学习笔记(深入)”;

  #1处发生的错误不仅仅是因为作用域规则导致,而且和Python以及其他很多编程语言中函数调用实现的机制有关.在此地方执行时间点并没有什么有效的语法可以获取变量x的值,因为压根就不存在,函数foo的命名空间随着函数的调用开始而开始,结束而销毁

5,函数参数

Python允许想函数传递参数,参数会变成本地变量存在与函数内部

#coding:UTF8def foo(x):     print locals()foo(1){'x': 1}

登录后复制

  在Python中有很多的方式来定义和传递参数,简要说明下:函数的参数是必须的位置参数或是可选的命名,默认参数

#coding:UTF8def foo(x, y=0): # 1     return x - y print foo(3, 1) # 22print foo(3) # 33print foo() # 4TypeError: foo() takes at least 1 argument (0 given)print foo(y=1, x=3) # 52

登录后复制

  

  在#1处定义了函数foo,有一个位置参数x和一个命名参数y 在#2通过常规的方式来调用函数,即使只有一个命名参数,但参数依然可以通过位置参数传递给函数.在调用函数的时候,对于命名参数y也可以完全不管就想#3所示一样.如命名参数没有接收到任何值的话,Python会自动使用声明的默认值.但不能省略第一个位置参数x,否则会像#4发生错误

python支持函数调用时的命名参数。看看#5处的函数调用,传递的是两个命名实参,这个时候因为有名称标识,参数传递的顺序也就不用在意了。

当然相反的情况也是正确的:函数的第二个形参是y,但通过位置的方式传递值给它。在#2处的函数调用foo(3,1),我们把3传递给了第一个参数,把1传递给了第二个参数,尽管第二个参数是一个命名参数。

6,嵌套函数

Python允许创建嵌套函数,就意味着可以在函数里定义函数而且现有的作用域和变量生存周期依旧适用

#coding:UTF8def outer():     x = 1     def inner():         print x # 1     inner() # 2 outer()1

登录后复制

  Python解释器需找一个叫x的本地变量,查找失败之后会继续向上层的作用域里查,这个上层的作用域定义在另外一个函数里,对于函数outer来说,变量x是一个本地变量
函数inner可以访问封闭的作用域.在#2处,可以调用函数inner,inner也仅仅是一个遵循Python变量解析规则的变量名,Python解释器会优先在outer的作用域里面对变量名inner查找匹配的变量

7,函数是Python世界中的一级类对象

在Python里函数和其他东西一样都是对象

#coding:UTF8print issubclass(int, object) # all objects in Python inherit from a common baseclassTruedef foo():     passprint foo.__class__ # 1print issubclass(foo.__class__, object)True

登录后复制

  

  函数在Python里就是对象,和其他一样,在Python里,函数只是一些普通的值而已,也就是说把函数像参数一样传递给其他的函数或者从函数里返回函数,如:

#coding:UTF8def add(x, y):     return x + ydef sub(x, y):     return x - ydef apply(func, x, y): # 1     return func(x, y) # 2print apply(add, 2, 1) # 33print apply(sub, 2, 1)1

登录后复制

  

  在#1处看到函数准备接收一个函数的变量,只是一个普通的变量而已,和其他变量一样,在#2处调用传进来的函数:”()代表这调用函数的操作并且调用变量包含额值.在#3处,能看到传递函数并没有特殊的用法”.函数的名称只是跟其他变量一样的标识符而已

Python把频繁要用的操作变成函数作为参数进行使用,向通过传递一个函数给内置排序函数的key参数 从而 来自定义排序规则

#coding:UTF8def outer():     def inner():         print "Inside inner"     return inner # 1 foo = outer() #2print foo foo()Inside inner

登录后复制

在#1处恰好是函数标识符的变量inner作为返回值返回出来 “把函数inner返回出来,否则它根本不可能会被调用到” 每次函数outer呗调用,函数inner都会被重新定义,如果它不被当做变量返回额话,每次执行过后将不复存在

在#2处捕获返回值–函数inner,将它存在一个新的变量foo里.当对foo进行求值,确定包含函数inner,而且能够对它进行调用

8,闭包

#coding:UTF8def outer():     x = 1     def inner():         print x # 1     return innerfoo = outer()print foo.func_closure(,)

登录后复制

 

立即学习“Python免费学习笔记(深入)”;

  x是outer里的一个局部变量,当函数inner在#1处打印x时,Python解释器会在inner内部查找相应的变量,事实也查不到,接着会到封闭作用域里查找,并且找到匹配

从变量的生存周期来看,变量x是函数outer的一个本地变量,意味着只有当函数outer正在运行时才会存在,根据Python运行模式,无法再函数outer返回之后继续调用函数inner,在函数inner调用时,变量x早已不复存在,可能会发生一个运行时的错误
但返回的函数inner可以继续工作,Python支持一个叫做函数闭包的特性,嵌套定义在非全局作用域里的函数能够记住它在被定义的时候它所处的封闭命名空间,这能够通过查看函数的func_closure属性得出结论,这个属性里面包含封闭作用域里面的值(只会包含被捕捉到的值,比如x,如果在outer里面还定义了其他的值,封闭作用域里面是不会有的)

每次函数outer被调用的时候,函数inner都会被重新定义。现在变量x的值不会变化,所以每次返回的函数inner会是同样的逻辑
稍微改动下:

#coding:UTF8def outer(x):     def inner():         print x # 1     return innerprint1 = outer(1)print2 = outer(2)print1()1print2()2

登录后复制

  从中可以看到闭包–被函数记住的封闭作用域–能够被用来创建自定义的函数,本质上是一个硬编码的参数.事实上并不是传递参数1或者2给函数inner,实际上是创建了能够打印各种数字的各种自定义版本

闭包单独拿出来就是一个非常强大的功能,在某些方面:outer像是给inner服务器的构造器,x像是一个私有变量

9,装饰器

装饰器其实就是一个闭包,把一个函数当做参数然后返回一个替代版参数

#coding:UTF8def outer(func):     def inner():         print "before func"         ret = func() # 1         return ret + 1     return innerdef foo():     return 1decorated = outer(foo) # 2print decorated()before func2

登录后复制

  

  定义了一个函数outer,只有一个func参数,在其定义了嵌套的函数inner,inner会打印一串字符串,然后调用func,在#1得到返回值,在outer每次调用时func值可能会不一样,但不管怎用,都会调用它,最后,inner返回func()+1的值,通过调用在#2处存储decorated里的函数能够看到被打印出来的字符串以及返回值2,而不是期望中调用函数foo得到的返回值1。

可以认为变量decorated是函数foo的一个装饰版本,一个加强版本。事实上如果打算写一个有用的装饰器的话,可能会想愿意用装饰版本完全取代原先的函数foo,这样总是会得到我们的”加强版“foo。想要达到这个效果,完全不需要学习新的语法,简单地赋值给变量foo就行了:

foo = outer(foo)

登录后复制

现在,任何怎么调用都不会牵扯到原先的函数foo,都会得到新的装饰版本的foo,现在还是来写一个有用的装饰器

#coding:UTF8import timedef bar():    time.sleep(2)    print('in the bar')def test2(func):    print(func)    return func# print(test2(bar))bar=test2(bar)bar()  #run barin the bar

登录后复制

  

10. 使用 @ 标识符将装饰器应用到函数和利用*args and **kwargs

Python2.4支持使用标识符@将装饰器应用在函数上,只需要在函数的定义前加上@和装饰器的名称。在上一节的例子里我们是将原本的方法用装饰后的方法代替:

bar=test2(bar)

登录后复制

这种方式能够在任何时候对任意方法进行包装。但是如果自定义一个方法,可以使用@进行装饰:

 1 #coding:UTF8 2  3 import time 4  5 def test2(func): 6     print(func) 7     return func 8 @test2 9 def bar():10     time.sleep(2)11     print('in the bar')12 13 bar()  #run bar

登录后复制

 

立即学习“Python免费学习笔记(深入)”;

 1 #coding:UTF8 2  3 import time 4 def timer(func): #timer(test1)  func=test1 5     def deco(*args,**kwargs): 6         start_time=time.time() 7         func(*args,**kwargs)   #run test1() 8         stop_time = time.time() 9         print("the func run time  is %s" %(stop_time-start_time))10     return deco11 @timer  #test1=timer(test1)12 def test1():13     time.sleep(1)14     print('in the test1')15 16 @timer # test2 = timer(test2)  = deco  test2(name) =deco(name)17 def test2(name,age):18     print("test2:",name,age)19 20 test1()21 test2("Tom",22)22 23 24 in the test125 the func run time  is 1.0520000457826 ('test2:', 'Tom', 22)27 the func run time  is 0.0

登录后复制

 

立即学习“Python免费学习笔记(深入)”;

下面贡献一个高级版的装饰器:

 1 #coding:utf8 2 import time 3 user,passwd = 'hbert','abc' 4 def auth(auth_type): 5     print("auth func:",auth_type) 6     def outer_wrapper(func): 7         def wrapper(*args, **kwargs): 8             #print("wrapper func args:", *args, **kwargs) 9             if auth_type == "local":10                 username = raw_input("Username:").strip()11                 password = raw_input("Password:").strip()12                 if user == username and passwd == password:13                     print("[32;1mUser has passed authentication[0m")14                     res = func(*args, **kwargs)  # from home15                     print("---after authenticaion ")16                     return res17                 else:18                     exit("[31;1mInvalid username or password[0m")19             elif auth_type == "ldap":20                 print("搞毛线ldap,不会。。。。")21 22         return wrapper23     return outer_wrapper24 25 def index():26     print("welcome to index page")27 @auth(auth_type="local") # home = wrapper()28 def home():29     print("welcome to home  page")30     return "from home"31 32 @auth(auth_type="ldap")33 def bbs():34     print("welcome to bbs  page")35 36 index()37 print(home()) #wrapper()38 bbs()

登录后复制

 

立即学习“Python免费学习笔记(深入)”;

以上就是Python装饰器的详细介绍的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2268246.html

(0)
上一篇 2025年2月27日 10:38:05
下一篇 2025年2月22日 18:33:09

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 日系电脑编程语言有哪些

    日系编程语言包括:Ruby:面向对象、动态语言,语法简洁优雅,用于 Web 开发、数据分析等。Python:解释型、高级语言,易用性高,广泛用于数据科学、机器学习、Web 开发。JavaScript:脚本语言,主要用于 Web 浏览器,允许…

    2025年2月27日
    200
  • 电脑上的c语言编程软件有哪些

    C 语言编程有许多软件可用,包括以下选项:免费软件:Code::Blocks、Dev-C++、MinGW、TIO商业软件:Microsoft Visual Studio、JetBrains CLion、Embarcadero RAD Stu…

    2025年2月27日
    200
  • 对比分析python下识别二维码用法和识别率

     最近项目中用到二维码图片识别,在python下二维码识别,目前主要有三个模块:zbar 、zbarlight、zxing。 1、三个模块的用法: #-*-coding=utf-8-*-import os import loggingimp…

    编程技术 2025年2月27日
    200
  • 电脑编程语言有哪些类型

    根据用途、功能和语法结构,电脑编程语言可分为几类:面向过程语言:强调数据结构和控制流,如 C、C++、Java、Python。面向对象语言:组织代码为对象,如 C++、Java、Python、C#。函数式语言:专注于数学函数应用,如 Has…

    2025年2月27日
    200
  • Python环境下安装MySQLdb模块

    ———————-【针对Windows下python 的MySQLdb模块安装】—————&#82…

    编程技术 2025年2月27日
    200
  • 电脑用的编程语言有哪些

    计算机编程语言是指导计算机执行任务的语言,允许将人类指令转换为机器代码。流行的编程语言包括:低级语言:汇编语言机器语言高级语言:PythonJavaC++C#JavaScriptSQL特定领域的语言: 电脑使用的编程语言 计算机编程语言是用…

    2025年2月27日
    200
  • Python–AES加密与解密方法指导

    起源: 视频下载,解析到一个网站时,发现其视频id是用AES加密过的,用的是这个库。解密很简单的一句js代码: t.video = CryptoJS.AES.decrypt(t.video, secret).toString(CryptoJ…

    编程技术 2025年2月27日
    200
  • 电脑编程主流语言有哪些

    目前最流行的电脑编程语言:1. Python(数据科学、机器学习);2. Java(企业级应用程序);3. C++(高性能应用程序);4. C#(Windows 应用程序);5. JavaScript(动态 Web 页面);6. SQL(数…

    2025年2月27日
    200
  • Python基础入门–函数

    8.函数 函数是带名字的代码块,用于完成具体的工作。def函数定义,指出函数名。定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了。对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数…

    编程技术 2025年2月27日
    200
  • python入门教程之列表操作

    python列表操作——增 append:追加一条数据到列表的最后 name = [“Zhangsan”,”XiongDa”,”Lisi”]name.append(“wangwu”)print name输出结果:[‘Zhangsan’, ‘…

    编程技术 2025年2月27日
    200

发表回复

登录后才能评论