一、isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
class Foo(object):
pass
obj = Foo()
print(isinstance(obj,Foo)) #True
issubclass(sub, super)检查sub类是否是 super 类的派生类
class Foo(object):
pass
class Bar(Foo):
pass
print(issubclass(Bar, Foo)) #True
二、反射
1、什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2、python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
判断object中有没有一个name字符串对应的方法或属性
1)hasattr:检测是否含有某种属性
class BlackMedium:
feturn ="Ugly"
def __init__(self,name,addr):
self.name =name
self.addr =addr
def sell_hourse(self):
print("【%s】正在买房子,傻瓜才买了" % self.name)
def rent_hourse(self):
print("【%s】正在租房子,傻瓜才租了" % self.name)
b1 = BlackMedium("万科","苏州")
#hasattr 查找b1能不能调用到类中的属性
print(hasattr(b1,"name")) #True
print(hasattr(b1,"sell_hourse"))#True
2)getattr:获取属性
class BlackMedium:
feturn ="Ugly"
def __init__(self,name,addr):
self.name =name
self.addr =addr
def sell_hourse(self):
print("【%s】正在买房子,傻瓜才买了" % self.name)
def rent_hourse(self):
print("【%s】正在租房子,傻瓜才租了" % self.name)
b1 = BlackMedium("万科","苏州")
print(getattr(b1,"name")) #T万科
print(getattr(b1,"sell_hourse"))#<bound method BlackMedium.sell_hourse of <__main__.BlackMedium object at 0x0289EA90>>
fun = getattr(b1,"sell_hourse")
fun() #【万科】正在买房子,傻瓜才买了
print(getattr(b1,"age")) #没有就会报错
print(getattr(b1,"age","没有这个属性")) #第三个是默认参数,如果找不到属性也不会报错,直接打出默认参数
3)setattr:设置属性,添加属性值,修改属性
class BlackMedium:
feturn ="Ugly"
def __init__(self,name,addr):
self.name =name
self.addr =addr
def sell_hourse(self):
print("【%s】正在买房子,傻瓜才买了" % self.name)
def rent_hourse(self):
print("【%s】正在租房子,傻瓜才租了" % self.name)
b1 = BlackMedium("万科","苏州")
setattr(b1,"age",True)
setattr(b1,"name","融创西苑")
print(b1.__dict__)
4)delattr:删除属性
class BlackMedium:
feturn ="Ugly"
def __init__(self,name,addr):
self.name =name
self.addr =addr
def sell_hourse(self):
print("【%s】正在买房子,傻瓜才买了" % self.name)
def rent_hourse(self):
print("【%s】正在租房子,傻瓜才租了" % self.name)
b1 = BlackMedium("万科","苏州")
setattr(b1,"age",True)
setattr(b1,"name","融创西苑")
delattr(b1,'show_name111')#不存在,则报错
print(b1.__dict__)
delattr(b1,"age")
print(b1.__dict__)
#结果
{'name': '融创西苑', 'addr': '苏州', 'age': True}
{'name': '融创西苑', 'addr': '苏州'}
补充:
1)类也是对象
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')) #old boy
print(getattr(Foo, 'func'))#<function Foo.func at 0x02BD9B28>
print(getattr(Foo, 'bar'))#<function Foo.bar at 0x02BD9B70>
2)反射当前模块成员
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import sys
def s1():
print('s1')
def s2():
print('s2')
this_module = sys.modules[__name__]
print(this_module)#<module '__main__' from 'D:/Pycharm Community/面向对象/b.py'>
print(hasattr(this_module, 's1'))#True
print(getattr(this_module, 's2'))#<function s2 at 0x01339AE0>
3)导入其他模块,利用反射查找该模块是否存在某个方法
module_test.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
def test():
print('from the test')
#!/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')()
3、为什么用反射之反射的好处
好处一:实现可插拔机制
有俩程序员,一个a,一个是b,a在写程序的时候需要用到b所写的类,但是b去跟女朋友度蜜月去了,还没有完成他写的类,a想到了反射,使用了反射机制a可以继续完成自己的代码,等b度蜜月回来后再继续完成类的定义并且去实现a想要的功能。
总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
b还没有实现全部功能
class FtpClient:
'ftp客户端,但是还么有实现具体的功能'
def __init__(self,addr):
print('正在连接服务器[%s]' %addr)
self.addr=addr
不影响a的代码编写
#from module import FtpClient
f1=FtpClient('192.168.1.1')
if hasattr(f1,'get'):
func_get=getattr(f1,'get')
func_get()
else:
print('---->不存在此方法')
print('处理其他的逻辑')
好处二:动态导入模块(基于反射当前模块成员)
三、__setattr__,__delattr__,__getattr__
__setattr__,__delattr__,__getattr__定义在类里面去实现的
class Foo:
x =1
def __init__(self,name):
self.name = name
def __getattr__(self, item):
print('----> from getattr:你找的属性不存在')
def __setattr__(self, key, value):
print('----> from setattr')
#self.key = value ##这就无限递归了,最后报错,递归就是递归__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)
# 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,
# #你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
print(f1.__dict__)
f1.z =3
print(f1.__dict__)
#__delattr__删除属性的时候会触发
f1.__dict__["a"]=3
print(f1.__dict__)
del f1.a
print(f1.__dict__)
#__getattr__只有在使用点调用属性且属性不存在的时候才会触发
print(f1.x)
print(getattr(f1,x))
f1.xxxxxxxxxxxxxxxxxxx #执行属性不存在的时候就会执行__getattr__这个函数属性
四、二次加工标准类型(包装)
包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)
二次加工标准类型(基于继承实现)
class List(list):
def append(self, p_object):
' 派生自己的append:加上类型检查'
if not isinstance(p_object,int):