反射 reflection 也有人称之为自省

作用:

运行时获取、添加对象的类型定义信息,包括类

内建方法:

getattr(object, name[, default])   返回object对象的name属性的值(name必须为字符串),当属性不存在时,将使用default返回,如果没有default,就会抛出AttributeError异常。
setattr(object, name, value)   设置object对象的name属性值,如果存在则覆盖,不存在就新增。
hasattr(object, name)     判断ojbect对象是否有name属性

魔术方法:

__getattr__         当通过搜索实例、实例的类及祖先类查找不到指定属性时调用此方法

__setattr__          通过.访问实例属性,进行增加、修改时调用此方法

__delattr__          当通过实例来删除属性时调用次方法

__getattribute__  实例所有的属性调用第一个都会调用该方法

三种动态增加属性的方式:

编译期:
  装饰器/Mixin
运行期:
  反射

  1. # 回顾下命令分发器
  2. def dispatcher():
  3. cmds = {}
  4. def reg(cmd,fn):
  5. if isinstance(cmd,str):
  6. cmds[cmd] = fn
  7. else:
  8. print('error')
  9.  
  10. def run():
  11. print(cmds.items())
  12. while True:
  13. cmd = input('>>>').strip()
  14. if cmd == 'quit':
  15. return
  16. cmds.get(cmd,defaultfn)()
  17.  
  18. def defaultfn():
  19. print('default')
  20.  
  21. return reg,run
  22.  
  23. reg,run = dispatcher()
  24.  
  25. reg('cmd1', lambda : print(1))
  26. reg('cmd2', lambda : print(2))
  27. print(run())

  

  1. # 将命令分发器改装成类
  2. class dispatcher:
  3.  
  4. def cmd1(self):
  5. return 'cmd1'
  6.  
  7. # def reg(self):
  8. # pass
  9.  
  10. def run(self):
  11. while True:
  12. cmd = input('>>>').strip()
  13. if cmd == 'quit':
  14. return
  15. print(getattr(self,cmd,self.default)())
  16.  
  17. def default(self):
  18. return 'default'
  19.  
  20. dis = dispatcher()
  21.  
  22. print(dis.run())

  

  1. # 使用反射为改造命令分发器
  2. class dispatcher:
  3.  
  4. def cmd1(self):
  5. return 'cmd1'
  6.  
  7. def reg(self,cmd,fn):
  8. if isinstance(cmd,str):
  9. # setattr(self,cmd.strip(),fn) #报TypeError异常,反射不会自动为实例自动绑定self参数
  10. setattr(self.__class__, cmd.strip(), fn) #为类添加属性,正常,观察运行结果__dict__的值
  11. else:
  12. return 'Error'
  13.  
  14. def run(self):
  15. print(dispatcher.__dict__)
  16. print(self.__dict__)
  17. while True:
  18. cmd = input('>>>').strip()
  19. if cmd == 'quit':
  20. return
  21. print(getattr(self,cmd,self.default)())
  22.  
  23. def default(self):
  24. return 'default'
  25.  
  26. dis = dispatcher()
  27. dis.reg('cmd2',lambda self: 'cmd2')
  28. dis.reg('cmd3',lambda self: 'cmd3')
  29. print(dis.run())

  

一个类的属性会按照继承关系找,如果找不到,就会执行__getattr__()方法,如果没有这个方法,就会抛出AttributeError异常表示找不到该属性。

查找属性顺序为:

instance.dict --> instance.class.dict --> 继承的祖先类(直到object类)的dict --> 调用__getattr__()

__getattr__() 魔术方法举例:

例一:

  1. # 类装饰器本质上就是调用__call__方法
  2. #
  3.  
  4. class A:
  5. def __init__(self,x):
  6. self.x = x
  7.  
  8. def __getattr__(self, item):
  9. return '__getitem__ {}'.format(item)
  10.  
  11. a = A(10)
  12. print(a.x)
  13. ---运行结果--
  14. 10

  

例二:

  1. # 找不到指定属性时就会调用__getattr__方法
  2. class A:
  3. def __init__(self,x):
  4. self.x = x
  5.  
  6. def __getattr__(self, item):
  7. return "missing: {}".format(item)
  8.  
  9. print(A(10).y)
  10. ---运行结果--
  11. missing: y

  

例三:

  1. # 继承情况下同样是找不到指定属性就调用__getattr__方法
  2. class Base:
  3. n = 17
  4.  
  5. class A(Base):
  6. m = 19
  7. def __init__(self,x):
  8. self.x = x
  9.  
  10. def __getattr__(self, item):
  11. return "missing: {}".format(item)
  12.  
  13. print(A(10).y)
  14. print(A(10).n)
  15. print(A(10).m)
  16. ------
  17. missing: y
  18. 17
  19. 19

  

__setattr__() 魔术方法举例:

可以拦截对实例属性的增加、修改操作,如果要设置生效,需要自己操作实例的__dict__。

  1. # 实例化时和,和实例化后,为属性赋值时就会调用__setattr__方法
  2. class Base:
  3. n = 17
  4.  
  5. class A(Base):
  6. m = 19
  7. def __init__(self,x):
  8. self.x = x
  9.  
  10. def __getattr__(self, item):
  11. return "__getattr__: {}".format(item)
  12. # return self.item
  13.  
  14. def __setattr__(self, key, value):
  15. # return "{},{}".format(key,value)
  16. # print('__setattr__:',key,value)
  17. self.__dict__[key] = value
  18. return self
  19.  
  20. a = A(10)
  21. print(1,a.y)
  22. print(2,a.n)
  23. print(3,a.m)
  24.  
  25. a.y = 100
  26. print(a.__dict__)
  27. print(4,a.y)
  28. ------运行结果---------
  29. 1 __getattr__: y
  30. 2 17
  31. 3 19
  32. {'y': 100, 'x': 10}
  33. 4 100

  

__delattr__() 魔术方法举例:

  1. # 删除实例属性时调用__delattr__方法
  2. class Base:
  3. n = 17
  4.  
  5. class A(Base):
  6. m = 19
  7. def __init__(self,x):
  8. self.x = x
  9.  
  10. def __getattr__(self, item):
  11. print(self.__dict__)
  12. return "__getattr__: {}".format(item)
  13. # print("__getattr__: {}".format(item))
  14. # return self.__dict__[item]
  15.  
  16. def __setattr__(self, key, value):
  17. # return "{},{}".format(key,value)
  18. # print('__setattr__:',key,value)
  19. self.__dict__[key] = value
  20. # print(self.__dict__)
  21. return self
  22.  
  23. def __delattr__(self, item):
  24. print('delattr:{}'.format(item))
  25. del self.__dict__[item] #删除的是实例的属性,不是类的属性
  26. # del self.__class__.__dict__[item] #测试是可以删除类的属性
  27. return self
  28.  
  29. a = A(10)
  30. print(1,a.y)
  31. print(2,a.n)
  32. print(3,a.m)
  33.  
  34. a.y = 100
  35. print(a.__dict__)
  36. print(4,a.y)
  37.  
  38. del a.y #只能删除实例属性,不能删除类属性
  39. # del a.m #无法删除类的属性,否则抛异常:TypeError: 'mappingproxy' object does not support item deletion
  40. print(a.__dict__)
  41. print(A.__dict__)
  42. ---运行结果----
  43. {'x': 10}
  44. 1 __getattr__: y
  45. 2 17
  46. 3 19
  47. {'y': 100, 'x': 10}
  48. 4 100
  49. delattr:y
  50. {'x': 10}
  51. {'__doc__': None, '__module__': '__main__', '__delattr__': <function A.__delattr__ at 0x00000152B9112F28>, '__getattr__': <function A.__getattr__ at 0x00000152B9112E18>, 'm': 19, '__init__': <function A.__init__ at 0x00000152B9112B70>, '__setattr__': <function A.__setattr__ at 0x00000152B9112EA0>}

  

  1. # 类的属性字典是一个mappingproxy对象
  2. # 参考:https://stackoverflow.com/questions/32720492/why-is-a-class-dict-a-mappingproxy
  3. In [1]: class A:
  4. ...: n = 5
  5. ...:
  6.  
  7. In [2]: a = A()
  8.  
  9. In [3]: a.n
  10. Out[3]: 5
  11.  
  12. In [5]: a.__dict__
  13. Out[5]: {}
  14.  
  15. In [6]: A.__dict__
  16. Out[6]:
  17. mappingproxy({'__dict__': <attribute '__dict__' of 'A' objects>,
  18. '__doc__': None,
  19. '__module__': '__main__',
  20. '__weakref__': <attribute '__weakref__' of 'A' objects>,
  21. 'n': 5})
  22.  
  23. In [7]: print(A.__dict__)
  24. {'n': 5, '__dict__': <attribute '__dict__' of 'A' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
  25.  
  26. In [11]: type(A.__dict__)
  27. Out[11]: mappingproxy
  28.  
  29. In [12]: type(type(A.__dict__))
  30. Out[12]: type

  

实例的所有属性访问,第一个都会调用__getattribute__方法,它阻止了属性的查找,该方法返回(计算后)的值或者抛出一个AttributeError异常。

它的return值将作为属性查找的结果。如果抛出AttributeError异常,则会调用__getattr__方法,因为表示属性没有找到。

__getattribute__ 方法举例:

拦截在字典查找之前

  1. # 访问一个属性时就会调用__getattribute__方法,找不到就返回AttributeError异常
  2. # 如果抛出了AttributeError异常,就会调用 __getattr__ 方法
  3. class Base:
  4. n = 17
  5.  
  6. class A(Base):
  7. m = 19
  8. def __init__(self,x):
  9. self.x = x
  10.  
  11. def __getattribute__(self, item):
  12. print('__getattribute__:',item)
  13. raise AttributeError
  14.  
  15. def __getattr__(self, item):
  16. return "__getattr__: {}".format(item)
  17.  
  18. def __setattr__(self, key, value):
  19. print('__setattr__:',key,value)
  20.  
  21. def __delattr__(self, item):
  22. print('delattr:{}'.format(item))
  23. if hasattr(self,item):
  24. print('{} has attribute {}'.format(self,item))
  25. del self.__dict__[item] #删除的是实例的属性,不是类的属性
  26. return self
  27.  
  28. a = A(10)
  29. print(a.y)
  30. -----运行结果-------
  31. __setattr__: x 10
  32. __getattribute__: y
  33. __getattr__: y

  

  

Python 面向对象(四) 反射及其魔术方法的更多相关文章

  1. Python面向对象之反射,双下方法

    一. 反射 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序 ...

  2. python 面向对象(四)反射

    ####################总结########## 1. isinstance: 判断xxx是否是xxx类型的(向上判断) type: 返回xx对象的数据类型 issubclass: 判 ...

  3. 百万年薪python之路 -- 面向对象之 反射,双下方法

    面向对象之 反射,双下方法 1. 反射 计算机科学领域主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省) python面向对象中的反射:通过字符串的形式操作对象相关的属性.python ...

  4. Python 面向对象之反射

    Python 面向对象之反射 TOC 什么是反射? hasattr getattr setattr delattr 哪些对象可以使用反射 反射的好处 例子一 例子二 什么是反射? 程序可以访问.检查和 ...

  5. Python面向对象之常用的特殊方法(5)

    Python面向对象里面有很多特殊方法,例如__init__(构造方法),__del__(析构方法),这些方法对于面向对象编程非常重要,下面列出一些常用的特殊方法 (1)__call__ class ...

  6. 第三十四篇 Python面向对象之 反射(自省)

    什么是反射? 反射的概念是由Smith在1982年提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序语 ...

  7. python 面向对象之反射及内置方法

    面向对象之反射及内置方法 一.静态方法(staticmethod)和类方法(classmethod) 类方法:有个默认参数cls,并且可以直接用类名去调用,可以与类属性交互(也就是可以使用类属性) 静 ...

  8. python面向对象进阶 反射 单例模式 以及python实现类似java接口功能

    本篇将详细介绍Python 类的成员.成员修饰符.类的特殊成员. 类的成员 类的成员可以分为三大类:字段.方法和特性. 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存 ...

  9. python 面向对象之多态与绑定方法

    多态与多态性 一,多态 1,多态指的是一类事物有多种形态(python里面原生多态) 1.1动物有多种形态:人,狗,猪 import abc class Animal(metaclass=abc.AB ...

随机推荐

  1. 关于python安装一些包时出现的错误解决方法

    1.关于wordcloud的安装 --win10,py3.6环境下安装总是出现安装错误,解决方法,下载wordcloud的wheel文件,进行安装. 详情参考:https://github.com/a ...

  2. Scrapy框架--使用cookie

    CookieMiddleware class scrapy.downloadermiddlewares.cookies.CookieMiddlewar 该中间件使得爬取需要cookie(例如使用ses ...

  3. Android Annotations Eclipse 配置 (3)

    Android Annotations 本来我想写个 Java 版本的<RESTful客户端库:RestClient>用于 Android 应用开发,结果发现不太好写,虽然用了 Dynam ...

  4. win10 uwp 通知列表

    经常看到小伙伴问,问已经绑定列表,在进行修改时,不会通知界面添加或删除.这时问题就在,一般使用的列表不会在添加时通知界面,因为他们没有通知. 本文:知道什么是通知的列表,如何去写一个通知列表 在 C# ...

  5. 怎么样防止Sql注入

    (1)对于动态构造SQL查询的场合,可以使用下面的技术: 第一:替换单引号,即把所有单独出现的单引号改成两个单引号,防止攻击者修改SQL命令的含义.再来看前面的例子,“SELECT * from Us ...

  6. ThreeJS之动画交互逻辑及特效

    工作需要,研究了一下 threejs 简单逻辑动画交互方法.写了一个小示例,分享一下,挺丑的. 第一步 当然就是初始化 threejs 的渲染场景了. var camera; //相机 var sce ...

  7. Python数据库查询之组合条件查询-F&Q查询

    F查询(取字段的值) 关于查询我们知道有filter( ) ,values( ) , get( ) ,exclude( ) ,如果是聚合分组,还会用到aggregate和annotate,甚至还有万能 ...

  8. ASP.NET Core中间件实现分布式 Session

    1. ASP.NET Core中间件详解 1.1. 中间件原理 1.1.1. 什么是中间件 1.1.2. 中间件执行过程 1.1.3. 中间件的配置 1.2. 依赖注入中间件 1.3. Cookies ...

  9. javascript 之执行环境-08

    概念 执行环境(Execution context,简称EC)或执行上下文对象(后面统一用执行上下文表示),它定义了变量或者函数有权访问的其他数据,决定了他们各自的行为.是不是有点不好理解,那我先简单 ...

  10. CodePath Android CliffNotes 之 Effective Java for Android 翻译

    概述: 这篇文章的目的是作为这篇博文的开源版本,而netcyrax是该指南的原始文章的唯一作者. 请在下面添加您自己的在Android中Java最佳实践.技巧和巧妙! 建造者模式 当你拥有一个需要超过 ...