Python装饰器的实现原理

  Python中的装饰器是通过利用了函数特性的闭包实现的,所以在说装饰器之前,我们需要先了解函数特性,以及闭包是怎么利用了函数特性的。

1.函数特性

  Python中的函数特性总的来说有四点:

    1.函数作为变量传递

def add(x):return x + 1a = add  

    2.函数作为参数传递

def add(x):return x + 1def excute(f):return f(3)excute(add)   

    3.函数作为返回值

def add(x):return x + 1def get_add():return add     

    4.函数嵌套及跨域访问

def outer():x = 1def inner():print(x)         inner()outer()

2.闭包的实现

  Python中的装饰器是通过闭包实现的,简单地讲,闭包就是引用了外部变量的内部函数,而闭包的实现正是利用了以上函数特性,下面我们来看看闭包是如何实现的:

 

def outer(x):def inner():                  # 函数嵌套return x                  # 跨域访问,引用了外部变量xreturn inner                  # 函数作为返回值closure = outer('外部变量')        # 函数作为变量赋给closure
print(closure())                  # 执行闭包#结果
外部变量

  在这个流程中,outer接收到'外部变量',传给inner,作为它return的参数,最后outer返回inner函数,返回的inner函数作为变量传递给closure,最后执行closure这个函数对象,实际上是执行了inner这个函数,返回了 '外部变量',这样就实现了一个简单的闭包。

  上面这个闭包例子只用到了之前说的三个函数特性,函数作为参数这个特性好像并没有用上,下面做一下延伸,把outer的参数x用一个函数对象替代

def func():return '函数func'def outer(x):def inner():                              # 函数嵌套return '戴了inner牌帽子的 ' + x()       # 跨域访问,引用了外部变量xreturn inner                              # 函数作为返回值closure = outer(func)                         # 函数func作为outer的参数;函数作为变量赋给closureprint(func())                                 # 执行原始函数
print(closure())                              # 执行闭包# 结果
函数func
戴了inner牌帽子的 函数func

  观察上面的例子,从func()到closure(),函数func就是被装饰了一番变成了clousre,分析一下具体过程:

  closure实际上是outer(func),func作为参数传进outer,outer的子函数inner对func返回的结果进行了一番装饰,返回了一个装饰后的结果,最后outer返回inner,可以说inner就是装饰后的func,这就是一个函数被装饰的过程,重点在于执行 outer(func) 这个步骤。

3.装饰器语法糖@

  Python给我们提供了语法糖 @,我们想执行 outer(func) 的时候,只需要把outer函数@到func函数的上面就可以了。

def outer(x):def inner():return '戴了inner牌帽子的 ' + x()return inner@outer
def func():return '函数func'print(func())#结果
戴了inner牌帽子的 函数func

   打印的结果跟我们执行closure()的结果是一样的,也就说明 加了outer装饰器的func 等价于 outer(func),所以我们很清楚地知道装饰器@的作用是什么了,就是拿来把被装饰的函数作为参数传递到装饰器函数里面加工的,最后执行被装饰函数的时候,就相当于执行了一个加工后的函数。

以上就是Python中装饰器的实现原理。

 

4.装饰器的使用

  Python中装饰器用处很多,下面写一个例子感受一下.

  类中的私有属性在类外部是无法访问的(就当无法访问好了,毕竟鬼叔是不推荐访问的),而这时可以在类中定义一个方法返回这个私有属性然后在外部调用就可以得到这个私有属性,但是这样看起来就和正常的调用属性的方式不一样了(obj.属性),这时候就可以用@property来实现想要的效果.

class Person:def __init__(self,name,age):self.name = nameif type(age) is int:self.__age = ageelse:print( '你输入的年龄的类型有误,请输入数字')@propertydef age(self):return self.__age@age.setterdef age(self,a):'''判断,你修改的年龄必须是数字'''if type(a) is int:self.__age = aelse:print('你输入的年龄的类型有误,请输入数字')@age.deleterdef age(self):del self.__agep1 = Person('帅哥',20)
print(p1.age)
del p1.age
用装饰器实现属性

 

转载于:https://www.cnblogs.com/luxiangyu111/p/9671395.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/396796.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

opengl 安装_如何使得支持 OpenGL 的 Flatpak 应用和游戏在专有 Nvidia 图形驱动下工作 | Linux 中国...

一些支持 OpenGL 并打包为 Flatpak 的应用和游戏无法使用专有 Nvidia 驱动启动。本文将介绍如何在不安装开源驱动(Nouveau)的情况下启动这些 Flatpak 应用或游戏。-- Logix这有个例子。我在我的 Ubuntu 18.04 桌面上使用专有的 Nvidia 驱动程序 (nvidia-driver-390)&#xff0c…

RequireJS入门(一)

RequireJS由James Burke创建,他也是AMD规范的创始人。 RequireJS会让你以不同于往常的方式去写JavaScript。你将不再使用script标签在HTML中引入JS文件,以及不用通过script标签顺序去管理依赖关系。 当然也不会有阻塞(blocking)的…

Oracle数据库中游标的游标的使用

本人不喜欢说概念啥的,就直接说明使用方法吧 案例1: 1 DECALRE2 --声明游标3 CURSOR C_USER(C_ID NUMBER) IS4 SELECT NAME FROM USER WHERE TYPEID C_ID;5 V_NAME C_USER%rowtype; --定义游标变量6 BEGIN7 OPEN C_USER(变量值); …

eclipse占用内存过大_idea被评最好用java开发工具,为什么用eclipse的人更多?

从事java开发一般都需要使用到一些开发工具,记得以前刚接触java的时候还用过MyEclipse。idea被评为最好用java开发工具,为什么用eclipse的人更多?下面一起来了解下吧!IDEA毕竟不便宜啊,很多企业都买不起只能用Eclipse了&#xff…

Asp.net mvc 知多少(六)

本系列主要翻译自《ASP.NET MVC Interview Questions and Answers 》- By Shailendra Chauhan,想看英文原版的可访问http://www.dotnettricks.com/free-ebooks自行下载。该书主要分为两部分,ASP.NET MVC 5、ASP.NET WEB API2。本书最大的特点是以面试问答…

selenium选错弹出层的下拉框

要先选中这个弹出层的form元素,再找下拉框 public void downSelectBox(){driver.get("https://www.imooc.com/user/setprofile");driver.findElement(By.className("pull-right")).click();try {Thread.sleep(2000);} catch (InterruptedExcept…

C语言 1A gt $20,C语言输出 1到20 的阶乘之和

除了调用库,绝对找不到比这更精简的代码了.#include#includelong long getdata(long long n){long long sum 1;while(n){sum*n--;}return sum;}int main(){long long sum 0;long long nums 20;while(nums){sumgetdata(nums--);}printf("%lld",sum);}【…

32位PLSQL Developer无法登录Oracle 11g 64位

问题: Windows10 64位下装Oracle 11g 64位,PLSQL Developer使用出现以下问题: 1、Database下拉框为空: 2、强制输入用户名、密码及Database,登录弹出: 说明PLSQL Developer并不支持Oracle 64位客户端连接。…

c语言课程结束,【计算机】程序设计——C语言基础秋季学期课程圆满结束

2019年10月22日11:40,在同学们发自内心的掌声中,课外培养中心开办的程序设计——C语言基础课程圆满落幕。本次课程由计算机中心的陶媛老师予以指导,在短短五次课的时间里,同学们对学习C语言都有了更深的体悟。对于大部…

struts2获取请求参数的三种方式及传递给JSP参数的方式

接上一篇文章package test;import com.opensymphony.xwork2.ActionSupport; import javax.servlet.http.*; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionContext; import java.util.*; public class HelloAction extends ActionSup…

CentOS6.5 搭建Open***服务器

前言:之前搭建过程中找了5-6个教程一起看,真是累,难道就没有写的详细一点,一次成功的吗,基于此花了一下午制作了本教程,实际测试2遍均成功,懒人福音。基础环境:系统:Cent…

python如何在exel中编程_如何使用Python以编程方式将行添加到现有Excel表中

尽管有各种各样的pythonexcel操作库和资源,但我无法找到具体的解决方案。在 现在,我有一个表格存在的Excel模板文件。我想编写一个Python程序来填充这个表。对于任何现有的Excel库都可以这样做吗?模板Excel文件包含一个空表的工作表&#xff…

c语言文件分屏显示,通用子目录文件显示方法

通用子目录文件显示方法在用CHKDS/V对磁盘子目录及子目录文件进行查找时,由于输出显示信息没有分屏显示,很容易错过需要的信息,并且显示信息没有标记出隐藏的子目录名及子目录文件名,这样就对进一步的子目录及文件操作带来许多不便。若辅以管道操作采用CHKDSK/V:|MORE,虽然可分…

Javascript、Dom、JQuery

1、Javascript JavaScript是一种属于网络的脚本语言,已经被广泛用于Web应用开发,常用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果。通常JavaScript脚本是通过嵌入在HTML中来实现自身的功能的。 1.1 存在形式 1 1、文件形式 2 <script src"../jqu…

mysql镜像_Mysql phpmyadmin docker镜像安装

前言1.介于mysql的安装很容易出现各种坑&#xff0c;本文使用 mysql 的docker镜像2.为了方便管理mysql数据库又不暴露mysql服务&#xff0c;所以使用phpmyadmin管理pull镜像#下载mysql镜像docker pull mysql#下载phpmyadmin镜像docker pull phpmyadmin/phpmyadmin创建网络docke…

linux安装lrzsz,并使用rz sz 命令

1 centeos中使用 yum -y install lrzsz 命令下载并安装 2 使用 rz 命令将windows文件上传到linux 3 使用 sz 命令将linux文件下载到windows 例如&#xff1a; 4 tar zcvf dbq.tar.gz files/ 打包指定文件夹 5 sz dbq.tar.gz 转载于:https://www.cnblogs.com/shaner/p/6387516.h…

慈不掌兵,义不行贾,烂好人难成大业!

两个月前&#xff0c;朋友的创业公司倒闭了。 朋友是温文尔雅的白面君子&#xff0c;有着光鲜的履历和出众的能力。和他聊天&#xff0c;永远觉得沐浴春风。温润如玉&#xff0c;充满魅力。 朋友细致而体贴。他记得你的生日时&#xff0c;并在那天给发送祝福和红包&#xff1b;…

c++如何打开hdf5文件_如何打开CSV格式文件才能正常使用?

正文开始前先给大家来一波福利&#xff0c;欢迎大家扫码关注后&#xff0c;手动发送“薪酬”领取《企业薪酬管理必备资料包》&#xff01;注意&#xff1a;先扫码关注再回复回复关键词&#xff01;先扫码关注再回复回复关键词&#xff01;先扫码关注再回复回复关键词&#xff0…

Linux驱动技术(四) _异步通知技术

异步通知的全称是"信号驱动的异步IO"&#xff0c;通过"信号"的方式&#xff0c;放期望获取的资源可用时&#xff0c;驱动会主动通知指定的应用程序&#xff0c;和应用层的"信号"相对应&#xff0c;这里使用的是信号"SIGIO"。操作步骤是…

go 类型断言_(57)接口的类型断言

GO提供了一个方法&#xff0c;用来判断接口的底层值是什么类型类型断言 提供了访问接口值底层具体值的方式。t : i.(T)该语句断言接口值 i 保存了具体类型 T&#xff0c;并将其底层类型为 T 的值赋予变量 t。若 i 并未保存 T 类型的值&#xff0c;该语句就会触发一个panic。为了…