判断对象是否是属于某个类的
isinstance(对象名, 类名)
注意: 如果是它的父类, 同样也返回True; 但是 (父类的对象, 子类) 返回的是Fale
查看父类, 注意是使用类名而不是对象
类名.__bases__
判断是否是某个类的子类
issubclass(子类名, 父类名)
2 反射
反射是指程序可以访问、检测和修改它本身状态或行为的一种能力
2.1 反射参数
可以通过不同的字符串来反射不同的参数, 进而进行一定的操作; 或者反射一些函数来执行
在Python中主要是使用内置函数hasattr, getattr, setattr, delattr三个函数
hassattr(), 判断对象或者类是否具有摸个参数, 第一个参数是类或者对象, 第二个参数是字符串类型的名字, 返回值是True或者False
class People:
def run(self):
print('running..')
print( hasattr(People() , 'run') )
print( hasattr(People , 'run') )
getattr(), 获取对象或者类的参数, 第一个参数是类或者对象, 第二个参数是字符串类型的名字,但是使用对象和类室友区别的
另外还可以设置第三个参数, 当该属性不存在的时候返回那个值
whc = People()
func = getattr(whc, 'run')
func()
func = getattr(People, 'run')
func(whc)
print( getattr(whc, 'running', '该属性不存在') )
setattr(), 设置属性, 同样可以给对象和类绑定
whc = People()
setattr(whc, 'name', 'weihuchao')
setattr(People, 'country', 'China')
print(whc.__dict__)
print(People.__dict__)
delattr(), 删除属性
delattr(whc, 'name')
delattr(People,'country')
print(whc.__dict__)
print(People.__dict__)
使用反射的好处, 可插拔机制
因为可以查看类中是否含有某属性, 在不同模块写程序的时候, 只需要判断该属性有没有就可使程序健壮的完成, 而不必要等待相关联的模块完成
2.2 反射模块
在正常使用的导入模块是使用import或者from, 但是要反射某个模块, 同样是根据输入的字符串的来反射
具体的反射有两种操作, 一个是内置函数__import__(), 另一个是使用模块importlib
具体模式如下
返回值 = __import__(模块名字字符串)
#或者
import importlib
返回值 = importlib.import_module(模块名字字符串)
返回值就是相当于反射回来的命名空间的名字
一般建议使用第二种方法
name = 'time'
nameSpace = __import__(name)
print(nameSpace.time())
#或者
import importlib
name = 'time'
nameSpace = importlib.import_module(name)
print(nameSpace.time())
3 __getattr__等
在类中, 还可以定义__getattr__(), __setattr__() 和 __deltattr__()
定义了__setattr__() 和 __deltattr__()函数之后, 类中所有的设置, 删除属性和方法的时候都会调用它
具体来说, 由于设置了这两个函数, 所以在完成设置和删除功能的时候, 不能再使用赋值语句和setattr()这个内置函数的处理了
要处理结果需要使用__dict__属性来完成
__setattr__() 默认有三个参数, 一个是self, 第二个是键, 第三个是值
__deltattr__()认有两个个参数,一个self, 另一个是需要删除的属性的名字
但是__getattr__()函数特殊, 它是在调用attr不存在的时候才调用, 基于这个特性有很强的使用效果
具体的实例如下
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
4 授权
授权是__getattr__()函数的应用
具体实例是实现一个记录日志的Open类
在__init__()函数中, 可以通过传入的内容来获得文件句柄, 再编写一个write()函数, 通过文件句柄写入日志信息即可
但是除了wirte()函数功能之外别的文件函数像close()和flush()等都不需要修改的, 但是总不能每一个都写一遍
所以利用__getattr__()不存在属性调用的特性, 利用__getattr__()有两个参数一个是self另一个就是获取的属性名这个特性, 通过内置函数getattr()来具体取得那些相关属性
具体代码如下
import time
class LogFile:
def __init__(self,filename,mode='r',encoding='utf-8'):
self.file=open(filename,mode,encoding=encoding)
def write(self,line):
t=time.strftime('%Y-%m-%d %T')
self.file.write('%s %s' %(t,line))
def __getattr__(self, item):
print("aaa")
return getattr(self.file,item)
f1=LogFile('log', 'w+')
f1.write('create logs..')
f1.seek(0)
print(f1.read())
f1.close()
5 包装
通过继承基本类型list, 来获得list的全部功能, 通过重写append()方法, 来加入对添加进来的值进行类型判断, 从而实现自定义功能
具体代码如下
class List(list):
def append(self, p_object):
if not isinstance(p_object,int):
raise TypeError('插入的值必须是int类型的!')
super().append(p_object)
myList = List([1,2,3,4])
print(myList)
myList.append(5)
print(myList)
try:
myList.append('test')
except:
print("输入值类型不正确")
print(myList)