python 的类装饰器
我们都知道python的函数有装饰器,那么类也有装饰器吗?有的,为什么没有呢,来看下代码吧
def out(args):def inner(cls):cls._args = argsreturn clsreturn innerclass Student:passprint(Student.__dict__) Student.name = "ALICE" print(Student.__dict__) ###来看下执行结果### {'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None} {'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None, 'name': 'ALICE'}
我们定义了一个空类Student,里面没有任何属性,第一次打印类的dict属性时候大家看到是没有任何属性的,只有类的特殊属性
然后我们增加了一个name属性,然后再打印一次dict属性,就看到有一个常规的name属性,属性值是ALICE
然后看最上面的函数,这个函数是个装饰函数,out函数接收常规str参数,当然不限制类型,你也可以传入int参数等等。
Inner函数的参数值是cls,也就是一个类,我们把类当做一个参数传进去,既然函数装饰器都可以把函数当做 参数传进去,类也可以当做参数传进去,在python里万物皆对象,只要是对象就是可以被传入的
cls._args = args 这里就是给这个类增加一个新属性,新属性是_args 并且值是形参args的实参值
然后最重要的来了,必须要有 return cls 不然的话下面的类的调用就要出问题了,一会我们测试下,因为给类增加新的属性后,一定要返回类,具体为什么,我们一会测试下就明白了
最后我们使用装饰器的@方式来装饰类,我们来看下代码与执行结果
def out(args):def inner(cls):cls._args = argsreturn clsreturn inner @out("TOM") ##=>>这里必须要带上args的实参 class Student:passprint(Student.__dict__) Student.name = "ALICE" print(Student.__dict__) ####执行结果如下##### {'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None, '_args': 'TOM'} {'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None, '_args': 'TOM', 'name': 'ALICE'}
我们可以看到,新增了_args属性,并且属性值是TOM。
我们来看下是否是在python内部新建了一个类?
def out(args):def inner(cls):cls._args = argsprint("The new class id is {}".format(id(cls)))return clsreturn inner @out("TOM") class Student:passprint("The old class id is {}".format(id(Student))) foo = out("TOM") foo(Student)###我们返回每个类的ID##### The new class id is 32509208 The old class id is 32509208 The new class id is 32509208
ID值完全相同,看来在内部并没有创建一个新类,只是装饰器给其增加了一个属性
我们来测试下,在装饰器函数内部如果不返回类也就是cls呢?
def out(args):def inner(cls):cls._args = argsprint("The new class id is {}".format(id(cls)))#return clsreturn inner @out("TOM") class Student:pass#print("The old class id is {}".format(id(Student))) #foo = out("TOM") #foo(Student) print(Student.__dict__) ###看下执行结果#### Traceback (most recent call last): The new class id is 7146776File "E:/python_learn/test1.py", line 15, in <module>print(Student.__dict__) AttributeError: 'NoneType' object has no attribute '__dict__'
为什么会是NoneType呢?因为在inner函数里没有返回值,所以是空类型,所以不能调用类的任何属性
看下面代码就明白了
def out(args):def inner(cls):cls._args = argsprint("The new class id is {}".format(id(cls)))return clsreturn inner #@out("TOM") class Student:passfoo = out("TOM") print(id(foo(Student))) print(foo(Student).__dict__) ###看下结果### The new class id is 32967960 32967960 The new class id is 32967960 {'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None, '_args': 'TOM'}
我们注释掉了@调用
直接以赋值的方式来调用
首先定义foo = out("TOM") ,此时foo的值是inner函数
print(foo(Student)) 这时是打印inner函数的返回值,如果inner函数没有return的话,那么inner函数的返回值就是None,还记得吗?如果函数不写return那么默认返回就是空None,这也就是为什么上面代码会报NoneType error 了。
在inner函数里,我们把Student类以参数方式传入,再用return返回Student类也就是形参cls,如果不返回的话,下面装饰调用就无法调用到了,调用过程和装饰器一样,所以必须有return cls
def out(args):def inner(cls):cls._args = argsprint("The new class id is {}".format(id(cls)))#return clsreturn inner #@out("TOM") class Student:passfoo = out("TOM") print(id(foo(Student))) print(foo(Student).__dict__)###注释掉return,一样的报错### The new class id is 32247064 1577322688 The new class id is 32247064 Traceback (most recent call last):File "E:/python_learn/test1.py", line 13, in <module>print(foo(Student).__dict__) AttributeError: 'NoneType' object has no attribute '__dict__'
然后下面的调用方式是不会出错的
def out(args):def inner(cls):cls._args = argsprint("The new class id is {}".format(id(cls)))#return clsreturn inner #@out("TOM") class Student:passfoo = out("TOM") print(id(foo(Student))) print(foo(Student)) #####来看下结果######## The new class id is 37621016 1577322688 The new class id is 37621016 None
看到了有个None了吗?那是inner函数的默认返回值,这样调用是不会出错的,因为你没调用特殊属性啊,比如__dict__属性,空类型一调用肯定出错啊,所以这里不调用就没事了
return cls 的作用是,你传入的cls参数是什么类型,它给你返回的也是什么类型,只不过你传入的参数类型是个类,返回的是个增加了一个新属性的类而已
可以测试下
def out(args):def inner(cls):cls._args = argsprint("The new class id is {}".format(id(cls)))print(type(cls))return clsreturn inner #@out("TOM") class Student:passfoo = out("TOM") print(id(foo(Student))) print(foo(Student)) ####看下执行结果### The new class id is 37883160 <class 'type'> 37883160 The new class id is 37883160 <class 'type'> <class '__main__.Student'> ###看到了吧,类型为class###
def out(args):def inner(cls):#cls._args = argsprint("The new class id is {}".format(id(cls)))print(type(cls))return clsreturn inner #@out("TOM") class Student:passfoo = out("TOM") print(id(foo("tools"))) #####传入的是str那么返回的也是str### The new class id is 32593504 <class 'str'> 32593504
总的来说,多实践出真知,才能明白其中的道理
在函数装饰器里,如果不返回任何值是不会报错的
def out(fn):def inner(args):print("这个是个装饰器,是用来装饰其他函数用的")ret = fn(args)print("******************")#return retreturn inner#@out def test(name):print("这个是fn函数,是被装饰的")return name #print(test("Bob")) foo = out(test) print(foo("JOke")) ####来看下结果#### 这个是个装饰器,是用来装饰其他函数用的 这个是fn函数,是被装饰的 ****************** None
下面也一样
def out(fn):def inner(args):print("这个是个装饰器,是用来装饰其他函数用的")ret = fn(args)print("******************")#return retreturn inner@out def test(name):print("这个是fn函数,是被装饰的")return name print(test("SBB")) ############### 这个是个装饰器,是用来装饰其他函数用的 这个是fn函数,是被装饰的 ****************** None
具体为什么,很简单,打印的是inner函数,只要inner函数是正确的,有没有返回值是无所谓的。
转载于:https://www.cnblogs.com/hh2737/p/9202759.html
python 的类装饰器相关推荐
- Python笔记-类装饰器
使用类装饰器还可以依靠类内部的__call__方法,但使用@形式将装饰器附加到函数上时,就会调用此方法. 如下代码: class Foo(object):def __init__(self, func ...
- python装饰器类-Python类装饰器
上次介绍了Python的函数装饰器,这次我们来讲一讲Python的类装饰器. Python的类装饰器基本语法如下: defdecorator(cls):print "6666666" ...
- python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解
2019独角兽企业重金招聘Python工程师标准>>> 1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过 ...
- python装饰器类-Python 装饰器、类装饰器、属性装饰器
今天来介绍一下python的装饰器. 1.首先来介绍一下简单的装饰器, def play(): return "i can play" if __name__ == '__main ...
- python类装饰器详解-Python类中的装饰器在当前类中的声明与调用详解
我的Python环境:3.7 在Python类里声明一个装饰器,并在这个类里调用这个装饰器. 代码如下: class Test(): xx = False def __init__(self): pa ...
- python类装饰器详解-Python类装饰器实现方法详解
本文实例讲述了Python类装饰器.分享给大家供大家参考,具体如下: 编写类装饰器 类装饰器类似于函数装饰器的概念,但它应用于类,它们可以用于管理类自身,或者用来拦截实例创建调用以管理实例. 单体类 ...
- python装饰器类-PYTHON里的装饰器能装饰类吗
扩展回答 如何理解python里的装饰器 通常可以理解它是一个hook 的回调函数. 或者是理解成python 留给二次开发的一个内置API. 一般是用回调和hook 方式实现的. 如何理解Pytho ...
- python类装饰器详解-python 中的装饰器详解
装饰器 闭包 闭包简单的来说就是一个函数,在该函数内部再定义一个函数,并且这个内部函数用到了外部变量(即是外部函数的参数),最终这个函数返回内部函数的引用,这就是闭包. def decorator(p ...
- python类装饰器详解-Python装饰器基础概念与用法详解
本文实例讲述了Python装饰器基础概念与用法.分享给大家供大家参考,具体如下: 装饰器基础 前面快速介绍了装饰器的语法,在这里,我们将深入装饰器内部工作机制,更详细更系统地介绍装饰器的内容,并学习自 ...
最新文章
- 程序员饭碗不保了?GPT-3 最强应用发布,动动手指就自动写代码的神器来了!...
- 2018年春季个人阅读计划
- ElementUI的表单验证及常用规则
- vfp如何比较两张表的关键字重复_Access开发中建表的基本原理和规范(上)
- 用线性单元(LinearUnit)实现工资预测的Python3代码
- vc++ 6.0 堆栈_在C ++中使用链接列表实现堆栈
- Android调试系列之dumpsys命令
- pytorch gpu版本下载
- IOS NSUserDefaults 讲解 用法
- pycharm忽略whitespace警告
- Java过滤器和拦截器的区别
- 通过crontab定时执行shell脚本教程
- android 微信 耗电吗,微信太耗电了怎么办?微信耗电的两种解决方案
- 咳血的独角兽丨互联网的幕后攻防
- 用ping ,mtr ,traceroute 进行网络丢包分析
- 机器学习中的特异性和敏感性
- 2022 CCF中国软件大会(CCF Chinasoft)“约束求解与定理证明”论坛成功召开
- 电子证据是计算机系统,电子证据计算机证据数字证据的概念辨析
- ES6之promise天气案例
- 计算机二级内容专科生,计算机二级证有没有用 专科生考了有啥作用
热门文章
- mongodb--GridFS
- 自制操作系统(十) 图像叠加处理
- jQuery表单对象属性过滤选择器
- C# Linq获取两个List或数组的差集交集
- 【转】Step By Step在VS2008中完整配置Ajax Toolkit的使用(配图)
- Python的Linux的入门,学习摘要。
- 3.1 if条件语句
- 3 当某个应用的CPU使用达到100%,该怎么办?
- Python 析构方法__del__
- spring boot api文档_精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用