我们都知道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 的类装饰器相关推荐

  1. Python笔记-类装饰器

    使用类装饰器还可以依靠类内部的__call__方法,但使用@形式将装饰器附加到函数上时,就会调用此方法. 如下代码: class Foo(object):def __init__(self, func ...

  2. python装饰器类-Python类装饰器

    上次介绍了Python的函数装饰器,这次我们来讲一讲Python的类装饰器. Python的类装饰器基本语法如下: defdecorator(cls):print "6666666" ...

  3. python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解

    2019独角兽企业重金招聘Python工程师标准>>> 1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过 ...

  4. python装饰器类-Python 装饰器、类装饰器、属性装饰器

    今天来介绍一下python的装饰器. 1.首先来介绍一下简单的装饰器, def play(): return "i can play" if __name__ == '__main ...

  5. python类装饰器详解-Python类中的装饰器在当前类中的声明与调用详解

    我的Python环境:3.7 在Python类里声明一个装饰器,并在这个类里调用这个装饰器. 代码如下: class Test(): xx = False def __init__(self): pa ...

  6. python类装饰器详解-Python类装饰器实现方法详解

    本文实例讲述了Python类装饰器.分享给大家供大家参考,具体如下: 编写类装饰器 类装饰器类似于函数装饰器的概念,但它应用于类,它们可以用于管理类自身,或者用来拦截实例创建调用以管理实例. 单体类 ...

  7. python装饰器类-PYTHON里的装饰器能装饰类吗

    扩展回答 如何理解python里的装饰器 通常可以理解它是一个hook 的回调函数. 或者是理解成python 留给二次开发的一个内置API. 一般是用回调和hook 方式实现的. 如何理解Pytho ...

  8. python类装饰器详解-python 中的装饰器详解

    装饰器 闭包 闭包简单的来说就是一个函数,在该函数内部再定义一个函数,并且这个内部函数用到了外部变量(即是外部函数的参数),最终这个函数返回内部函数的引用,这就是闭包. def decorator(p ...

  9. python类装饰器详解-Python装饰器基础概念与用法详解

    本文实例讲述了Python装饰器基础概念与用法.分享给大家供大家参考,具体如下: 装饰器基础 前面快速介绍了装饰器的语法,在这里,我们将深入装饰器内部工作机制,更详细更系统地介绍装饰器的内容,并学习自 ...

最新文章

  1. 程序员饭碗不保了?GPT-3 最强应用发布,动动手指就自动写代码的神器来了!...
  2. 2018年春季个人阅读计划
  3. ElementUI的表单验证及常用规则
  4. vfp如何比较两张表的关键字重复_Access开发中建表的基本原理和规范(上)
  5. 用线性单元(LinearUnit)实现工资预测的Python3代码
  6. vc++ 6.0 堆栈_在C ++中使用链接列表实现堆栈
  7. Android调试系列之dumpsys命令
  8. pytorch gpu版本下载
  9. IOS NSUserDefaults 讲解 用法
  10. pycharm忽略whitespace警告
  11. Java过滤器和拦截器的区别
  12. 通过crontab定时执行shell脚本教程
  13. android 微信 耗电吗,微信太耗电了怎么办?微信耗电的两种解决方案
  14. 咳血的独角兽丨互联网的幕后攻防
  15. 用ping ,mtr ,traceroute 进行网络丢包分析
  16. 机器学习中的特异性和敏感性
  17. 2022 CCF中国软件大会(CCF Chinasoft)“约束求解与定理证明”论坛成功召开
  18. 电子证据是计算机系统,电子证据计算机证据数字证据的概念辨析
  19. ES6之promise天气案例
  20. 计算机二级内容专科生,计算机二级证有没有用 专科生考了有啥作用

热门文章

  1. mongodb--GridFS
  2. 自制操作系统(十) 图像叠加处理
  3. jQuery表单对象属性过滤选择器
  4. C# Linq获取两个List或数组的差集交集
  5. 【转】Step By Step在VS2008中完整配置Ajax Toolkit的使用(配图)
  6. Python的Linux的入门,学习摘要。
  7. 3.1 if条件语句
  8. 3 当某个应用的CPU使用达到100%,该怎么办?
  9. Python 析构方法__del__
  10. spring boot api文档_精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用