Python之面向对象反射

  isinstance(obj,cls)检查是否obj是否是类 cls 的对象  

1 class Foo(object):
2 pass
3
4 obj = Foo()
5
6 isinstance(obj, Foo)

  issubclass(sub, super)检查sub类是否是 super 类的派生类

class Foo(object):
pass class Bar(Foo):
pass issubclass(Bar, Foo)

  反射:

1 什么是反射

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

四个可以实现自省的函数

下列方法适用于类和对象(一切皆对象,类本身也是一个对象)

hasattr(object,name)
判断object中有没有一个name字符串对应的方法或属性
 def getattr(object, name, default=None): # known special case of getattr
"""
getattr(object, name[, default]) -> value Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
When a default argument is given, it is returned when the attribute doesn't
exist; without it, an exception is raised in that case.
"""
pass

getattr(object, name, default=None)

 def setattr(x, y, v): # real signature unknown; restored from __doc__
"""
Sets the named attribute on the given object to the specified value. setattr(x, 'y', v) is equivalent to ``x.y = v''
"""
pass

setattr(x, y, v)

 def delattr(x, y): # real signature unknown; restored from __doc__
"""
Deletes the named attribute from the given object. delattr(x, 'y') is equivalent to ``del x.y''
"""
pass

delattr(x, y)

 class BlackMedium:
feature='Ugly'
def __init__(self,name,addr):
self.name=name
self.addr=addr def sell_house(self):
print('%s 黑中介卖房子啦,傻逼才买呢,但是谁能证明自己不傻逼' %self.name)
def rent_house(self):
print('%s 黑中介租房子啦,傻逼才租呢' %self.name) b1=BlackMedium('万成置地','回龙观天露园') #检测是否含有某属性
print(hasattr(b1,'name'))
print(hasattr(b1,'sell_house')) #获取属性
n=getattr(b1,'name')
print(n)
func=getattr(b1,'rent_house')
func() # getattr(b1,'aaaaaaaa') #报错
print(getattr(b1,'aaaaaaaa','不存在啊')) #设置属性
setattr(b1,'sb',True)
setattr(b1,'show_name',lambda self:self.name+'sb')
print(b1.__dict__)
print(b1.show_name(b1)) #删除属性
delattr(b1,'addr')
delattr(b1,'show_name')
delattr(b1,'show_name111')#不存在,则报错 print(b1.__dict__)

四个方法的使用演示

 class Foo(object):

     staticField = "old boy"

     def __init__(self):
self.name = 'wupeiqi' def func(self):
return 'func' @staticmethod
def bar():
return 'bar' print getattr(Foo, 'staticField')
print getattr(Foo, 'func')
print getattr(Foo, 'bar')

类也是对象

 #!/usr/bin/env python
# -*- coding:utf-8 -*- import sys def s1():
print 's1' def s2():
print 's2' this_module = sys.modules[__name__] hasattr(this_module, 's1')
getattr(this_module, 's2')

反射当前模块成员

导入其他模块,利用反射查找该模块是否存在某个方法

 #!/usr/bin/env python
# -*- coding:utf-8 -*- def test():
print('from the test')

module_test.py

 #!/usr/bin/env python
# -*- coding:utf-8 -*- """
程序目录:
module_test.py
index.py 当前文件:
index.py
""" import module_test as obj #obj.test() print(hasattr(obj,'test')) getattr(obj,'test')()
 class People:
country='China'
def __init__(self,name):
self.name=name
# def walk(self):
# print('%s is walking' %self.name)
p=People('egon')
#
# People.country
# print(People.__dict__) # print(p.name)
# print(p.__dict__) # p.name #hasattr
# print('name' in p.__dict__)
# print(hasattr(p,'name'))
# print(hasattr(p,'name1213')) # print(hasattr(p,'country')) #p.country
# print(hasattr(People,'country')) #People.country
# print(hasattr(People,'__init__')) #People.__init__ #getattr
# res=getattr(p,'country') #res=p.country
# print(res)
#
# f=getattr(p,'walk') #t=p.walk
# print(f)
#
# f1=getattr(People,'walk')
# print(f1)
#
# f()
# f1(p) # print(p.xxxxxxx)
# print(getattr(p,'xxxxxxxx','这个属性确实不存在')) #
# if hasattr(p,'walk'):
# func=getattr(p,'walk')
# func()
#
# print('================>')
# print('================>') #setattr # p.sex='male'
# print(p.sex)
# print(p.__dict__) # setattr(p,'age',18)
# print(p.__dict__)
# print(p.age)
# print(getattr(p,'age')) #delattr
# print(p.__dict__)
# del p.name
# print(p.__dict__) print(p.__dict__)
delattr(p,'name')
print(p.__dict__)

3 为什么用反射之反射的好处

好处一:实现可插拔机制

有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。

总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能

 class FtpClient:
'ftp客户端,但是还么有实现具体的功能'
def __init__(self,addr):
print('正在连接服务器[%s]' %addr)
self.addr=addr

还没有实现全部功能

 #from module import FtpClient
f1=FtpClient('192.168.1.1')
if hasattr(f1,'get'):
func_get=getattr(f1,'get')
func_get()
else:
print('---->不存在此方法')
print('处理其他的逻辑')

不影响lili的代码编写

好处二:动态导入模块(基于反射当前模块成员)

  反射的用途:

    

import sys
def add():
print('add') def change():
print('change') def search():
print('search') def delete():
print('delete') this_module=sys.modules[__name__]
while True:
cmd=input('>>:').strip()
if not cmd:continue
if hasattr(this_module,cmd):
func=getattr(this_module,cmd)
func()
# if cmd in func_dic: #hasattr()
# func=func_dic.get(cmd) #func=getattr()
# func() # func_dic={
# 'add':add,
# 'change':change,
# 'search':search,
# 'delete':delete
# } # while True:
# cmd=input('>>:').strip()
# if not cmd:continue
# if cmd in func_dic: #hasattr()
# func=func_dic.get(cmd) #func=getattr()
# func() # class Foo:
# x=1
# def __init__(self,name):
# self.name=name # def walk(self):
# print('walking......')
# f=Foo('egon') # Foo.__dict__={'x':1,'walk':....}
# 'x' in Foo.__dict__ #hasattr(Foo,'x')
# Foo.__dict__['x'] #getattr(Foo,'x')
# print(Foo.x) #'x' in Foo.__dict__

  反射实现可插拔机制:

    FTP Server:

 import ftpclient
#
# print(ftpclient)
# print(ftpclient.FtpClient)
# obj=ftpclient.FtpClient('192.168.1.3')
#
# print(obj)
# obj.test() #
f1=ftpclient.FtpClient('192.168.1.1')
if hasattr(f1,'get'):
func=getattr(f1,'get')
func()
else:
print('其他逻辑')

    FTP Client:

 class FtpClient:
'ftp客户端,但是还么有实现具体的功能'
def __init__(self,addr):
print('正在连接服务器[%s]' %addr)
self.addr=addr
def test(self):
print('test') def get(self):
print('get------->')

  通过字符串导入模块:

# m=input("请输入你要导入的模块:")

# m1=__import__(m)  #官方不推荐
# print(m1)      #官方不推荐
# print(m1.time())  #官方不推荐 #官方推荐使用方法
import importlib
t=importlib.import_module('time')
print(t.time())

  attr系列:

  __getattr__、__setattr__、__delattr__

  setattr:为对象设置属性的时候回触发setattr的运行。

 getattr:只有在使用点调用属性且属性不存在的时候才会触发
 class Foo:
x=1
def __init__(self,y):
self.y=y def __getattr__(self, item):
print('----> from getattr:你找的属性不存在') def __setattr__(self, key, value):
print('----> from setattr')
# self.key=value #这就无限递归了,你好好想想
# self.__dict__[key]=value #应该使用它 def __delattr__(self, item):
print('----> from delattr')
# del self.item #无限递归了
self.__dict__.pop(item) #__setattr__添加/修改属性会触发它的执行
f1=Foo(10)
print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
f1.z=3
print(f1.__dict__) #__delattr__删除属性的时候会触发
f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
del f1.a
print(f1.__dict__) #__getattr__只有在使用点调用属性且属性不存在的时候才会触发
f1.xxxxxx

三者的用法演示

  定制自己的数据类型:    

# l=list([1,2,3])
#
# l.append(4)
# l.append('5')
# print(l) # class List(list):
# pass
#
# l1=List([1,2,3])
# print(l1)
# l1.append(4)
# print(l1)
# l1.append('5')
# print(l1) #基于继承的原理,来定制自己的数据类型(继承标准类型) # class List(list):
# def append(self, p_object):
# # print('--->',p_object)
# if not isinstance(p_object,int):
# raise TypeError('must be int')
# # self.append(p_object)
# super().append(p_object)
# def insert(self, index, p_object):
# if not isinstance(p_object,int):
# raise TypeError('must be int')
# # self.append(p_object)
# super().insert(index,p_object)
#
# l=List([1,2,3])
# # print(l)
# # l.append(4)
# # print(l)
#
# # l.append('5')
# print(l)
# # l.insert(0,-1)
# l.insert(0,'-1123123213')
# print(l) # def test(x:int,y:int)->int:
# return x+y
# print(test.__annotations__)
#
# print(test(1,2))
# print(test(1,'3'))
#
# def test(x,y):
# return x+y #不能用继承,来实现open函数的功能
# f=open('a.txt','w')
# print(f)
# f.write('1111111') #授权的方式实现定制自己的数据类型
import time class Open:
def __init__(self,filepath,m='r',encode='utf-8'):
self.x=open(filepath,mode=m,encoding=encode) self.filepath=filepath
self.mode=m
self.encoding=encode def write(self,line):
print('f自己的write',line)
t=time.strftime('%Y-%m-%d %X')
self.x.write('%s %s' %(t,line)) def __getattr__(self, item):
# print('=------>',item,type(item))
return getattr(self.x,item)
#
# f=Open('b.txt','w')
# # print(f)
# f.write('111111\n')
# f.write('111111\n')
# f.write('111111\n') f=Open('b.txt','r+')
# print(f.write)
print(f.read) res=f.read() #self.x.read()
print(res) print('=-=====>',f.read())
f.seek(0)
print(f.read())
# f.flush()
# f.close() 

  作业:

 #基于继承来定制自己的数据类型
class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid
def append(self, p_object):
' 派生自己的append:加上类型检查'
if not isinstance(p_object,int):
raise TypeError('must be int')
super().append(p_object)
#
@property
def mid(self):
'新增自己的属性'
index=len(self)//2
return self[index] # l=List([1,2,3]) # print(l.mid) #基于授权来定制自己的数据类型: # class Open:
# def __init__(self,filepath,mode,encode='utf-8'):
# self.f=open(filepath,mode=mode,encoding=encode)
# self.filepath=filepath
# self.mode=mode
# self.encoding=encode # def write(self,line):
# print('write')
# self.f.write(line) # def __getattr__(self, item):
# return getattr(self.f,item) # # f=Open('a.txt','w')
# # f.write('123123123123123\n')
# # print(f.seek)
# # f.close()
# #
# # f.write('111111\n') # f=open('b.txt','w')
# f.write('bbbbbb\n')
# f.close()
# print(f) # class Foo:
# def test(self):
# pass
#
# print(getattr(Foo,'test'))
#
# obj=Foo()
# print(getattr(obj,'test')) class List:
def __init__(self,x):
self.seq=list(x) def append(self,value):
if not isinstance(value,str):
raise TypeError('must be str')
self.seq.append(value)
@property
def mid(self):
index=len(self.seq)//2
return self.seq[index]
def __getattr__(self, item):
return getattr(self.seq,item) def __str__(self):
return str(self.seq) l=List([1,2,3]) l.append('') print(l.mid)
l.insert(0,123123123123123123123123123)
# print(l.seq) print(l) obj.name='egon'
del obj.name

链接:详细

最新文章

  1. Hibernate实现有两种配置,xml配置与注释配置
  2. 部署步骤“回收 IIS 应用程序池”中出现错误: <nativehr>0x80070005</nativehr><nativestack></nativestack>拒绝访问。
  3. 5.ScrollView无法填充满屏幕
  4. 微信js接口自定义分享内容
  5. js高程笔记1-3章
  6. Axure RP Pro 6.5修改站点地图,只显示需要的节点
  7. [WebKit]浏览器的加载与页面性能优化
  8. jQuery 树形结构
  9. xsoup,Jsoup
  10. 【二分贪心】Bzoj3969 [WF2013] Low Power
  11. .net webapi 后台导出excel 申请付款单实例
  12. JS垃圾收集机制
  13. 对类的理解(c++)
  14. c#单元测试:使用Moq框架Mock对象
  15. tensorflow进阶篇-4(损失函数2)
  16. Asp.Net里关于Session过期跳转页面的一些小技巧
  17. 开发常见错误之 : IMP-00058: 遇到 ORACLE 错误 1691
  18. django的queryset和objects对象
  19. Object C学习笔记4-内存管理
  20. Delphi报的错误

热门文章

  1. bzoj 3676: [Apio2014]回文串【后缀自动机+manacher】
  2. jQuery笔记之Easing Plugin
  3. 1.1.1最短路(Floyd、Dijstra、BellmanFord)
  4. 循环队列 分类: c/c++ 2014-10-10 23:28 605人阅读 评论(0) 收藏
  5. C#模版学习研究
  6. 多个文本框点击复制 zClip (ZeroClipboard)有关问题
  7. 可变类型的安全性——更锋利的C#代码小记(2)
  8. 把List<Map<String,Object>>转成Map<String,Object>
  9. AJPFX总结mysql复制表结构,表数据
  10. P1118 [USACO06FEB]数字三角形Backward Digit Su…