Python 面向对象(四) 反射及其魔术方法
反射 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
运行期:
反射
- # 回顾下命令分发器
- def dispatcher():
- cmds = {}
- def reg(cmd,fn):
- if isinstance(cmd,str):
- cmds[cmd] = fn
- else:
- print('error')
- def run():
- print(cmds.items())
- while True:
- cmd = input('>>>').strip()
- if cmd == 'quit':
- return
- cmds.get(cmd,defaultfn)()
- def defaultfn():
- print('default')
- return reg,run
- reg,run = dispatcher()
- reg('cmd1', lambda : print(1))
- reg('cmd2', lambda : print(2))
- print(run())
- # 将命令分发器改装成类
- class dispatcher:
- def cmd1(self):
- return 'cmd1'
- # def reg(self):
- # pass
- def run(self):
- while True:
- cmd = input('>>>').strip()
- if cmd == 'quit':
- return
- print(getattr(self,cmd,self.default)())
- def default(self):
- return 'default'
- dis = dispatcher()
- print(dis.run())
- # 使用反射为改造命令分发器
- class dispatcher:
- def cmd1(self):
- return 'cmd1'
- def reg(self,cmd,fn):
- if isinstance(cmd,str):
- # setattr(self,cmd.strip(),fn) #报TypeError异常,反射不会自动为实例自动绑定self参数
- setattr(self.__class__, cmd.strip(), fn) #为类添加属性,正常,观察运行结果__dict__的值
- else:
- return 'Error'
- def run(self):
- print(dispatcher.__dict__)
- print(self.__dict__)
- while True:
- cmd = input('>>>').strip()
- if cmd == 'quit':
- return
- print(getattr(self,cmd,self.default)())
- def default(self):
- return 'default'
- dis = dispatcher()
- dis.reg('cmd2',lambda self: 'cmd2')
- dis.reg('cmd3',lambda self: 'cmd3')
- print(dis.run())
一个类的属性会按照继承关系找,如果找不到,就会执行__getattr__()方法,如果没有这个方法,就会抛出AttributeError异常表示找不到该属性。
查找属性顺序为:
instance.dict --> instance.class.dict --> 继承的祖先类(直到object类)的dict --> 调用__getattr__()
__getattr__() 魔术方法举例:
例一:
- # 类装饰器本质上就是调用__call__方法
- #
- class A:
- def __init__(self,x):
- self.x = x
- def __getattr__(self, item):
- return '__getitem__ {}'.format(item)
- a = A(10)
- print(a.x)
- ---运行结果--
- 10
例二:
- # 找不到指定属性时就会调用__getattr__方法
- class A:
- def __init__(self,x):
- self.x = x
- def __getattr__(self, item):
- return "missing: {}".format(item)
- print(A(10).y)
- ---运行结果--
- missing: y
例三:
- # 继承情况下同样是找不到指定属性就调用__getattr__方法
- class Base:
- n = 17
- class A(Base):
- m = 19
- def __init__(self,x):
- self.x = x
- def __getattr__(self, item):
- return "missing: {}".format(item)
- print(A(10).y)
- print(A(10).n)
- print(A(10).m)
- ------
- missing: y
- 17
- 19
__setattr__() 魔术方法举例:
可以拦截对实例属性的增加、修改操作,如果要设置生效,需要自己操作实例的__dict__。
- # 实例化时和,和实例化后,为属性赋值时就会调用__setattr__方法
- class Base:
- n = 17
- class A(Base):
- m = 19
- def __init__(self,x):
- self.x = x
- def __getattr__(self, item):
- return "__getattr__: {}".format(item)
- # return self.item
- def __setattr__(self, key, value):
- # return "{},{}".format(key,value)
- # print('__setattr__:',key,value)
- self.__dict__[key] = value
- return self
- a = A(10)
- print(1,a.y)
- print(2,a.n)
- print(3,a.m)
- a.y = 100
- print(a.__dict__)
- print(4,a.y)
- ------运行结果---------
- 1 __getattr__: y
- 2 17
- 3 19
- {'y': 100, 'x': 10}
- 4 100
__delattr__() 魔术方法举例:
- # 删除实例属性时调用__delattr__方法
- class Base:
- n = 17
- class A(Base):
- m = 19
- def __init__(self,x):
- self.x = x
- def __getattr__(self, item):
- print(self.__dict__)
- return "__getattr__: {}".format(item)
- # print("__getattr__: {}".format(item))
- # return self.__dict__[item]
- def __setattr__(self, key, value):
- # return "{},{}".format(key,value)
- # print('__setattr__:',key,value)
- self.__dict__[key] = value
- # print(self.__dict__)
- return self
- def __delattr__(self, item):
- print('delattr:{}'.format(item))
- del self.__dict__[item] #删除的是实例的属性,不是类的属性
- # del self.__class__.__dict__[item] #测试是可以删除类的属性
- return self
- a = A(10)
- print(1,a.y)
- print(2,a.n)
- print(3,a.m)
- a.y = 100
- print(a.__dict__)
- print(4,a.y)
- del a.y #只能删除实例属性,不能删除类属性
- # del a.m #无法删除类的属性,否则抛异常:TypeError: 'mappingproxy' object does not support item deletion
- print(a.__dict__)
- print(A.__dict__)
- ---运行结果----
- {'x': 10}
- 1 __getattr__: y
- 2 17
- 3 19
- {'y': 100, 'x': 10}
- 4 100
- delattr:y
- {'x': 10}
- {'__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>}
- # 类的属性字典是一个mappingproxy对象
- # 参考:https://stackoverflow.com/questions/32720492/why-is-a-class-dict-a-mappingproxy
- In [1]: class A:
- ...: n = 5
- ...:
- In [2]: a = A()
- In [3]: a.n
- Out[3]: 5
- In [5]: a.__dict__
- Out[5]: {}
- In [6]: A.__dict__
- Out[6]:
- mappingproxy({'__dict__': <attribute '__dict__' of 'A' objects>,
- '__doc__': None,
- '__module__': '__main__',
- '__weakref__': <attribute '__weakref__' of 'A' objects>,
- 'n': 5})
- In [7]: print(A.__dict__)
- {'n': 5, '__dict__': <attribute '__dict__' of 'A' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
- In [11]: type(A.__dict__)
- Out[11]: mappingproxy
- In [12]: type(type(A.__dict__))
- Out[12]: type
实例的所有属性访问,第一个都会调用__getattribute__方法,它阻止了属性的查找,该方法返回(计算后)的值或者抛出一个AttributeError异常。
它的return值将作为属性查找的结果。如果抛出AttributeError异常,则会调用__getattr__方法,因为表示属性没有找到。
__getattribute__ 方法举例:
拦截在字典查找之前
- # 访问一个属性时就会调用__getattribute__方法,找不到就返回AttributeError异常
- # 如果抛出了AttributeError异常,就会调用 __getattr__ 方法
- class Base:
- n = 17
- class A(Base):
- m = 19
- def __init__(self,x):
- self.x = x
- def __getattribute__(self, item):
- print('__getattribute__:',item)
- raise AttributeError
- def __getattr__(self, item):
- return "__getattr__: {}".format(item)
- def __setattr__(self, key, value):
- print('__setattr__:',key,value)
- def __delattr__(self, item):
- print('delattr:{}'.format(item))
- if hasattr(self,item):
- print('{} has attribute {}'.format(self,item))
- del self.__dict__[item] #删除的是实例的属性,不是类的属性
- return self
- a = A(10)
- print(a.y)
- -----运行结果-------
- __setattr__: x 10
- __getattribute__: y
- __getattr__: y
Python 面向对象(四) 反射及其魔术方法的更多相关文章
- Python面向对象之反射,双下方法
一. 反射 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序 ...
- python 面向对象(四)反射
####################总结########## 1. isinstance: 判断xxx是否是xxx类型的(向上判断) type: 返回xx对象的数据类型 issubclass: 判 ...
- 百万年薪python之路 -- 面向对象之 反射,双下方法
面向对象之 反射,双下方法 1. 反射 计算机科学领域主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省) python面向对象中的反射:通过字符串的形式操作对象相关的属性.python ...
- Python 面向对象之反射
Python 面向对象之反射 TOC 什么是反射? hasattr getattr setattr delattr 哪些对象可以使用反射 反射的好处 例子一 例子二 什么是反射? 程序可以访问.检查和 ...
- Python面向对象之常用的特殊方法(5)
Python面向对象里面有很多特殊方法,例如__init__(构造方法),__del__(析构方法),这些方法对于面向对象编程非常重要,下面列出一些常用的特殊方法 (1)__call__ class ...
- 第三十四篇 Python面向对象之 反射(自省)
什么是反射? 反射的概念是由Smith在1982年提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序语 ...
- python 面向对象之反射及内置方法
面向对象之反射及内置方法 一.静态方法(staticmethod)和类方法(classmethod) 类方法:有个默认参数cls,并且可以直接用类名去调用,可以与类属性交互(也就是可以使用类属性) 静 ...
- python面向对象进阶 反射 单例模式 以及python实现类似java接口功能
本篇将详细介绍Python 类的成员.成员修饰符.类的特殊成员. 类的成员 类的成员可以分为三大类:字段.方法和特性. 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存 ...
- python 面向对象之多态与绑定方法
多态与多态性 一,多态 1,多态指的是一类事物有多种形态(python里面原生多态) 1.1动物有多种形态:人,狗,猪 import abc class Animal(metaclass=abc.AB ...
随机推荐
- 关于python安装一些包时出现的错误解决方法
1.关于wordcloud的安装 --win10,py3.6环境下安装总是出现安装错误,解决方法,下载wordcloud的wheel文件,进行安装. 详情参考:https://github.com/a ...
- Scrapy框架--使用cookie
CookieMiddleware class scrapy.downloadermiddlewares.cookies.CookieMiddlewar 该中间件使得爬取需要cookie(例如使用ses ...
- Android Annotations Eclipse 配置 (3)
Android Annotations 本来我想写个 Java 版本的<RESTful客户端库:RestClient>用于 Android 应用开发,结果发现不太好写,虽然用了 Dynam ...
- win10 uwp 通知列表
经常看到小伙伴问,问已经绑定列表,在进行修改时,不会通知界面添加或删除.这时问题就在,一般使用的列表不会在添加时通知界面,因为他们没有通知. 本文:知道什么是通知的列表,如何去写一个通知列表 在 C# ...
- 怎么样防止Sql注入
(1)对于动态构造SQL查询的场合,可以使用下面的技术: 第一:替换单引号,即把所有单独出现的单引号改成两个单引号,防止攻击者修改SQL命令的含义.再来看前面的例子,“SELECT * from Us ...
- ThreeJS之动画交互逻辑及特效
工作需要,研究了一下 threejs 简单逻辑动画交互方法.写了一个小示例,分享一下,挺丑的. 第一步 当然就是初始化 threejs 的渲染场景了. var camera; //相机 var sce ...
- Python数据库查询之组合条件查询-F&Q查询
F查询(取字段的值) 关于查询我们知道有filter( ) ,values( ) , get( ) ,exclude( ) ,如果是聚合分组,还会用到aggregate和annotate,甚至还有万能 ...
- ASP.NET Core中间件实现分布式 Session
1. ASP.NET Core中间件详解 1.1. 中间件原理 1.1.1. 什么是中间件 1.1.2. 中间件执行过程 1.1.3. 中间件的配置 1.2. 依赖注入中间件 1.3. Cookies ...
- javascript 之执行环境-08
概念 执行环境(Execution context,简称EC)或执行上下文对象(后面统一用执行上下文表示),它定义了变量或者函数有权访问的其他数据,决定了他们各自的行为.是不是有点不好理解,那我先简单 ...
- CodePath Android CliffNotes 之 Effective Java for Android 翻译
概述: 这篇文章的目的是作为这篇博文的开源版本,而netcyrax是该指南的原始文章的唯一作者. 请在下面添加您自己的在Android中Java最佳实践.技巧和巧妙! 建造者模式 当你拥有一个需要超过 ...