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 ...
随机推荐
- 国内为什么没有好的 Stack Overflow 的模仿者?,因为素质太低?没有分享精神?
今天终于在下班前搞定一个技术问题,可以准时下班啦.当然又是通过StackOverflow找到的解决思路,所以下班路上和同事顺便聊起了它,两个资深老程序猿,还是有点感叹,中国的程序员群体人数应该不少,为 ...
- 组件 layui 常用控件输入框
一.普通输入框 input <div class="layui-form-item"> <label class="layui-form-label&q ...
- git subtree pull 错误 Working tree has modifications
git subtree 是不错的东西,用于 git 管理子项目. 本文记录我遇到问题和翻译网上的答案. 当我开始 pull 的时候,使用下面的代码 git subtree pull --prefix= ...
- UWP win10 app 新关键字x:Bing
原本使用MVVM开发,我们使用数据绑定是x:Binging 新的关键字x:Bing使用和原来x:Binging区别不大. <TextBox x:Name="textBox" ...
- springcloud干货之服务消费者(ribbon)
本章介绍springcloud中的服务消费者 springcloud服务调用方式有两种实现方式: 1,restTemplate+ribbon, 2,feign 本来想一篇讲完,发现篇幅有点长,所以本章 ...
- mysql 中翻页
万变不离其中 select * from tableName where 条件 limit 当前页码*页面容量-1 , 页面容量
- es6总结
主要包括let const,模板字符串,解构赋值,箭头函数,扩展运算符,Promise,类,import export等 一.let和const 1.let所声明的变量只在let所在的代码块内有效.l ...
- eclipse中project facet问题
一般出现在从别处import的项目上,只有项目文件夹上有红叉,其他地方都正常,现总结个人的几个解决方案: 有几种可能: 1,编码设置是否一致,也即是你项目原来的编码和现在eclipse用的默认编码是否 ...
- iOS 之 runtime --- 集百家之言
runtime runtime用在什么地方? 说法 在程序运行过程中,动态的创建一个类(比如KVO的底层实现) 在程序运行过程中,动态地为某个类添加属性.方法,修改属性值\方法(method swiz ...
- 白皮书之C++学习第一天
大三荒废了一年的时间在lol上,上头了吧.后悔也来不及了,总之我会拼命追回来的! 今天重拾起这本白皮书,也是很感慨啊! 废话不多说,好好学,好好找工作吧!大三结束了啊! 每个C++程序都有一个main ...