1 isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls) obj是否是cls的对象或cls子类的对象
issubclass(sub,super) sub是否是super的子类
cls.__bases__ 获取cls的父类
class A:
pass
class B(A):
pass
print(issubclass(B,A)) #True
print(B.__bases__)
b=B()
print(isinstance(b,B)) #True
2 反射
反射也叫自省,主要设置程序可以访问、检测和修改它本身状态或行为的一种能力。
2.1 python中面向对象的反射
Python中是通过字符串的形式来操作对象相关的属性。python 中一切皆对象(都可以使用反射)
具体的做法是:将字符串映射成命令
四个实现自省的函数
2.1.1 hasattr
hasattr(object,name)
判断object是否有名字是name的属性。
等价于 name in object.__dict__
#!/user/bin/env python
# -*- coding:utf-8 -*-
class Foo:
camp="foo"
def __init__(self,name):
self.name=name
def test1(self):
print("test1")
f=Foo("zzz")
#不用反射来,访问属性
# print(f.name)
# f.name="yyy"
# print(f.name)
#使用反射
#hasattr
print(f.__dict__)
print(hasattr(f,"name")) #判断f对象的名称空间里,有么有"name"这个属性,等价于"name" in f.__dict__
print("name" in f.__dict__) #True
print("camp" in Foo.__dict__) #True
2.1.2 getattr
getattr(object, name, default=None)
获取object名称空间里的"name"属性的值,如果存在,就返回该值;不存在,就返回default。
等价于:object.name
(object.__dict__["name"]
)
#getattr
print(f.name)
print(getattr(f,"name")) #获取f对象名称空间里"name"属性的值,等价于 f.name <======> f.__dict__["name"]
print(getattr(f,"age",-1)) #获取f对象名称空间里"age"属性的值,如果不存在,就返回-1
#print(f.age) #AttributeError: 'Foo' object has no attribute 'age'
print(Foo.camp) #foo
print(Foo.__dict__["camp"]) #foo
### 2.1.3 setattr
setattr(object, name, value)
修改对象object的name属性值为value。
等价于:object.name=value
#setattr
setattr(f,"name","yyy") #等价于f.name="yyy" <=====>f.__dict__["name"]="yyy"
print(getattr(f,"name"))
setattr(Foo,"camp","fooo")
Foo.camp="fooo"
#Foo.__dict__["camp"]="fooo" #TypeError: 'mappingproxy' object does not support item assignment
print(getattr(Foo,"camp"))
2.1.4 delattr
delattr(object,name)
删除object对象的名称空间下的名叫name的属性
等价于:del object.name
#delattr
delattr(f,"name") #等价于del f.name <=====>f.__dict__.pop("name")
#print(f.name)
2.2 反射的两种形式
2.2.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'))
print(getattr(Foo,'func'))
print(getattr(Foo,'bar'))
结果:
old boy
<function Foo.func at 0x000001EDF525BB70>
<function Foo.bar at 0x000001EDF525BBF8>
2.2.2 基于模块的反射
在python中,每一个.py文件都是一个模块,而模块都是一个个对象。
#!/user/bin/env python
# -*- coding:utf-8 -*-
import sys
class Foo:
def __init__(self,name):
self.name = name
def get_name(self):
return self.name
#获取模块的名称
#print(__name__)
this_module=sys.modules[__name__]
print(this_module) #获取本文件的模块对象,通过该对象可以调用本文件下的变量、函数、类等
#print(sys.modules)
print(hasattr(this_module,"Foo"))
print(getattr(this_module,"Foo"))
结果:
__main__
<module '__main__' from 'D:/devtools/workspace/python/PycharmProjects/py_fulstack_s4/day32 面向对象的进阶/基于模块的反射.py'>
True
<class '__main__.Foo'>
2.3 反射的用途(好处)
2.3.1 实现可插拔机制
可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能。
#!/user/bin/env python
# -*- coding:utf-8 -*-
class FtpClient:
def __init__(self, addr):
print("正在连接服务器[%s]" % addr)
self.addr = addr
#def get():
#!/user/bin/env python
# -*- coding:utf-8 -*-
from developer_one import FtpClient
f1=FtpClient("192.168.1.1")
if hasattr(f1,"get"):
func_get=getattr(f1,"get")
func_get()
else:
print("不存在此方法")
print("处理其他的逻辑")
#即使调用的developer_one中FtpClient模块的功能“get”有没有完成,都不影响程序的正常执行。这就叫可插拔机制。
2.3.2 用字符串导入模块
m=input(">>").strip() #官方不推荐
m1=__import__(m)
print(m1.time())
import importlib #官方推荐方案
t=importlib.import_module("time")
2.4 日常中的“反射”
#!/user/bin/env python
# -*- coding:utf-8 -*-
def delete():
print("delete")
def add():
print("add")
def search():
print("search")
def modify():
print("modify")
file_dict={ #相当于对象的名称空间
"delete":delete,
"add":add,
"search":search,
"modify":modify,
}
while True:
choice=input(">>:").strip()
if not choice:continue
if choice in file_dict: #相当于hasattr(file_dict,choice)
func=file_dict[choice] #getattr(file_dict,choice)
func()
3 __setattr__,__delattr__,__getattr__
3.1 __setattr__
__setattr__ #在对象进行赋值(包括类的初始化)操作时,会自动调用
#!/user/bin/env python
# -*- coding:utf-8 -*-
class Foo:
def __init__(self,name):
self.name=name
def __setattr__(self, key, value): #对对象的属性进行赋值(包括类的初始化)操作时,会自动调用
print("key : %s , value : %s "%(key,value)) #key : name , value : zhang
print("key type:",type(key)) #key type: <class 'str'>
#为什么key的类型是str? 我们说了什么时候会自动调用这个函数。是在对象进行赋值的时候,其中有赋值操作的是,初始化f时。f=Foo("zhang"),在内存里面真正执行的是:f.__dict__["name"]="zhang"。所以说key是一个str类型。
print("value type:",type(value)) #value type: <class 'str'>
#print(self.key) #AttributeError: 'Foo' object has no attribute 'key'
#self.key=value #RecursionError: maximum recursion depth exceeded
#setattr(self,key,value) #RecursionError: maximum recursion depth exceeded
self.__dict__[key]=value
f=Foo("zhang")
结果:
key : name , value : zhang
key type: <class 'str'>
value type: <class 'str'>
__getattr__ age
3.2 __delattr__
__delattr__是在执行删除del object.name时,自动调用
class Foo:
def __init__(self,name):
self.name=name
def __delattr__(self,item): #在执行对象属性的删除操作时,会调用
#del self.item #RecursionError: maximum recursion depth exceeded while calling a Python object
#del self.__dict__[item]
self.__dict__.pop(item)
f=Foo("zhang")
del f.name
#print(f.name)
3.3 __getattr__
__getattr__ 查找的对象属性不存在,才会触发__getattr__;查找的对象属性存在,不会触发
class Foo:
def __init__(self,name):
self.name=name
def __getattr__(self,item): #查找的对象属性不存在,才会触发__getattr__;查找的对象属性存在,不会触发
print("__getattr__",item)
f=Foo("zhang")
f.name #未执行__getattr__
f.age #__getattr__ age
#print(f.name)
结果:
__getattr__ age
3.4 用途
1 二次加工标准类型
关键在于继承。
class List(list):
def append(self, obj):
if not isinstance(obj,int):
raise TypeError("must be int!")
super().append(obj)
def insert(self, index, obj):
if not isinstance(obj,int):
raise TypeError("must be int!")
super().insert(index,obj)
li=List((1,2,3))
#li.insert(2,"-1")
li.insert(2,-1)
print(li)
2 以授权的方式实现定制数据类型
#!/user/bin/env python
# -*- coding:utf-8 -*-
class List:
def __init__(self,li):
self.x=list(li)
def append(self,s):
if isinstance(s,str):
self.x.append(s)
else:
raise TypeError("传入列表的必须是字符串!")
@property
def mid(self):
print("列表的中间值:",self.x[int(len(self.x)/2)])
def __getattr__(self,item):
if hasattr(self.x,item):
return getattr(self.x,item)
else:
raise NameError("属性名错误!")
def __str__(self): #通过__str__来隐藏.x
return str(self.x)
li=List((1,2,3,4))
li.append("s")
print(li)
li.mid
li.pop(3)
print(li)
结果:
[1, 2, 3, 4, 's']
列表的中间值: 3
[1, 2, 3, 's']