目录
__setattr__、__delattr__、__getattr__方法
反射是什么?
反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力,在python中一切皆对象(类,实例,模块等等都是对象),那么我们就可以通过反射的形式操作对象相关的属性。
Python中的反射主要方法:
1.hasattr(object,name)
判断对象中有没有一个name字符串对应的方法或属性
2.getattr(object, name, default=None)
获取对象name字符串属性的值,如果不存在返回default的值
3.setattr(object, key, value)
设置对象的key属性为value值,等同于object.key = value
4.delattr(object, name)
删除对象的name字符串属性
方法的使用
class Map:
f1 = '召唤师峡谷'
def __init__(self,name,addr):
self.name = name
self.addr = addr
def from1(self):
print('%s来自%s'%(self.name,self.addr))
def from2(self):
print('%s选手是%s'%(self.addr,self.name))
b1 = Map('盖伦','上路')
#检测是否含有某属性;
print(hasattr(b1,'name')) #True
print(hasattr(b1,'from1')) #True
#获取属性;
n = getattr(b1,'name')
print(n) #盖伦
func = getattr(b1,'from1')
func() #盖伦来自上路
#getattr(b1,'abcsdf') #报错
print(getattr(b1,'xxxxxxx','不存在')) #不存在
#设置属性;
setattr(b1,'ADC','下路')
print(b1.__dict__) #{'name': '盖伦', 'addr': '上路', 'ADC': '下路'}
setattr(b1,'贵族','VN'+'奥巴驴')
print(b1.__dict__) #{'name': '盖伦', 'addr': '上路', 'ADC': '下路', '贵族': 'VN奥巴驴'}
#删除属性
delattr(b1,'addr')
print(b1.__dict__) #{'name': '盖伦', 'ADC': '下路', '贵族': 'VN奥巴驴'}
delattr(b1,'ADC')
print(b1.__dict__) #{'name': '盖伦', '贵族': 'VN奥巴驴'}
类也是对象
class Foo(object):
test = 'hello world!'
def __init__(self):
self.name = 'xuan'
def func(self):
return 'func'
@staticmethod
def bar():
return 'bar'
print(getattr(Foo,'test')) #hello world!
print(getattr(Foo,'func')) #<function Foo.func at 0x000001FF2457E048>
print(getattr(Foo,'bar')) #<function Foo.bar at 0x000001FF2457E0D8>
反射当前模块成员
import sys
def s1():
print("s1")
def s2():
print("s2")
this_module = sys.modules[__name__]
print(hasattr(this_module,'s1')) #True
print(getattr(this_module,'s2')) #<function s2 at 0x0000016B892E5EE8>
foo = getattr(this_module,'s2')
foo() #s2
动态导入模块(基于反射当前模块成员)
t.py
Dy_module.py
h = __import__('m1.t') #=====================
print(h) #<module 'm1' (namespace)>
h.t.test1() #test1
h.t.test2() #test2
import importlib
k = importlib.import_module('m1.t')
print(k) #<module 'm1.t' from 'G:\\pycharm\\Exercise\\2019.08\\m1\\t.py'>
k.test1() #test1
k.test2() #test2
__setattr__、__delattr__、__getattr__方法
class Foo:
def __init__(self,name):
self.name = name
def __getattr__(self,item):
print('您找的属性【%s】不存在'%item)
def __setattr__(self,h,k):
#print('执行setattr',h,k)
if type(k) is str: #要求字符串类型;
print("开始设置")
self.__dict__[h] = k.upper() #写入字典并设置大写;
else:
print("必须是字符串类型")
def __delattr__(self,item):
print("不允许删除属性【%s】"%item)
f1 = Foo('xuan')
f1.age = '20' #触发__setattr__
print(f1.__dict__)
print(f1.name)
print(f1.age)
print(f1.gender)
print(f1.slary)
del f1.name
print(f1.__dict__)
执行结果:
开始设置
开始设置
{'name': 'XUAN', 'age': '20'}
XUAN
20
您找的属性【gender】不存在
None
您找的属性【slary】不存在
None
不允许删除属性【name】
{'name': 'XUAN', 'age': '20'}
二次加工标准类型(包装)
包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知。
class List(list):
def append(self,p_object):
if type(p_object) is str:
super().append(p_object)
else:
print("只能添加字符串类型")
def show_midlle(self):
mid_index = int(len(self)/2)
return self[mid_index]
l1 = List('helloworld')
print(l1,type(l1)) #['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'] <class '__main__.List'>
print(l1.show_midlle()) # w
l1.append(11111111) #只能添加字符串类型;
l1.append('2222222') #['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', '2222222']
print(l1)
授权
授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。实现授权的关键点就是覆盖__getattr__方法;
import time
class FileHandle:
def __init__(self,filename,mode='r',encoding='utf-8'):
self.file=open(filename,mode,encoding=encoding)
self.mode=mode
self.encoding=encoding
def write(self,line):
t=time.strftime('%Y-%m-%d %X')
self.file.write('%s %s'%(t,line))
def __getattr__(self,item):
return getattr(self.file,item)
f1 = FileHandle('error.log','w+')
print(f1.file) #<_io.TextIOWrapper name='error.log' mode='w+' encoding='utf-8'>
print(f1.__dict__) #{'file': <_io.TextIOWrapper name='error.log' mode='w+' encoding='utf-8'>, 'mode': 'w+', 'encoding': 'utf-8'}
print('======>>',f1.read) #======>> <built-in method read of _io.TextIOWrapper object at 0x03283030>
f1.write('hello world!\n')
f1.write('CPU温度过高\n')
f1.write('内存不足\n')
f1.write('磁盘空间不足\n')
isinstance和issubclass方法
class Foo:
pass
class Bar(Foo):
pass
b1 = Bar()
print(isinstance(b1,Bar))
print(isinstance(b1,Foo))
print(type(b1))
print(issubclass(Bar,Foo)) #判断Bar是否是Foo的子类;
print(issubclass(Foo,Bar)) #判断Foo是否是Bar的子类;
执行结果:
True
True
<class '__main__.Bar'>
True
False
item方法
class Foo:
def __getitem__(self,item):
print('getitem',item)
return self.__dict__[item]
def __setitem__(self,key,value):
print('setitem')
self.__dict__[key] = value
def __delitem__(self,key):
print('delitem')
self.__dict__.pop(key)
f1 = Foo()
print(f1.__dict__) #{}
f1['name'] = 'xuan' #setitem
f1['age'] = 20 #setitem
print(f1.__dict__) #{'name': 'xuan', 'age': 20}
del f1['age'] #delitem
print(f1.__dict__) #{'name': 'xuan'}
print(f1['name']) #getitem name xuan
改变对象的字符串显示
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
return '名字是%s 年龄是%s'%(self.name,self.age)
f1 = Foo('xuan',20)
print(f1) #名字是xuan 年龄是20
x = str(f1)
print(x) #名字是xuan 年龄是20
y = f1.__str__()
print(y) #名字是xuan 年龄是20
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
# def __str__(self): #有str会直接执行str方法;
# return '这是str'
def __repr__(self):
return '名字是%s 年龄是%s'%(self.name,self.age)
f1 = Foo('xuan',20)
# print(f1) #这是str
print(f1) #名字是xuan 年龄是20
参考:https://www.cnblogs.com/linhaifeng/articles/6204014.html#_label3