一. 反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)
在Python中反射的表现形式是:
通过字符串的形式操作对象相关的属性
在Python中通过四个函数实现反射:
函数名 | 意义 |
---|---|
hasattr(obj,name) |
判断object中有没有一个name字符串对应的方法或属性 |
getattr(obj,name, default) |
检查obj.__dict__ 中有没有name 这个键值,有则不做任何处理,没有则报错 |
setattr(obj,name,value) |
等价于obj.name=value
|
delattr(obj,name) |
等价于del obj.name
|
class People:
country = 'China'
def __init__(self, name, gender):
self.name = name
self.gender = gender
def eat(self):
print('%s is eating' % self.name)
def sleep(self):
print('% is sleeping' % self.name)
p1=People('Jack', 'male')
#检测是否含有某属性
print(hasattr(p1, 'name'))
print(hasattr(p1, 'eat'))
>>True
>>True
#获取属性
n = getattr(p1, 'name')
print(n)
func = getattr(p1, 'eat')
func()
getattr(p1, 'aaaaaaaa') #报错
print(getattr(p1, 'aaaaaaaa', 'not exist'))
>>Jack
>>Jack is eating
>>not exist
#设置属性
setattr(p1, 'Joe', 'female')
setattr(p1, 'run', lambda self: self.name+' is running')
print(p1.__dict__)
print(p1.run(p1))
>>{'name': 'Jack', 'gender': 'male', 'Joe': 'female', 'run': <function <lambda> at 0x0000021D2B3E3E18>}
>>Jack is running
#删除属性
print(p1.__dict__)
delattr(p1, 'name')
print(p1.__dict__)
>> {'name': 'Jack', 'gender': 'male'}
>>{'gender': 'male'}
#只能删除对象的属性,如果是类那么只能删类的方法,如果是类实例化的对象只能删实例化对象的属性不能删类的,比如说执行delattr(p1, 'eat')会报错,如果删除的属性不存在也报错
反射当前模块成员
import sys
def s1():
print('s1')
def s2():
print('s2')
this_module = sys.modules[__name__]
print(hasattr(this_module, 's1'))
print(getattr(this_module, 's2'))
使用反射的用途
可插拔
可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用
建立``ftpClient.py`模块
class FtpClient: # 仅定义,不实现具体方法
def __init__(self, addr):
print('正在连接服务器[%s]' % addr)
self.addr = addr
建立ftpServer.py
模块
from ftpClient import FtpClient
f1=FtpClient('192.168.1.1')
if hasattr(f1,'get'):
func_get=getattr(f1,'get')
func_get()
else:
print('not exist')
>>正在连接服务器[192.168.1.1]
not exist
动态导入模块
通过字符串名称导入模块
import importlib
t = importlib.import_module('time')
print(t.time())
二. attr内置函数
__setattr__, __delattr__,__getattr__
class Foo:
def __init__(self, name):
self.name = name
def __setattr__(self, key, value):
print('running __setattr__')
self.__dict__[key] = value
def __getattr__(self, item):
print('running __getattr__')
pass
def __delattr__(self, item):
print('running __delattr__')
self.__dict__.pop(item)
f = Foo('Jack')
print(f.__dict__)
f.name = 'Jax'
print(f.__dict__)
del f.name
print(f.__dict__)
f.xxx #调用不存在的属性时才会触发__getattr__
>>running __setattr__
>>{'name': 'Jack'}
>>running __setattr__
>>{'name': 'Jax'}
>>running __delattr__
>>{}
>>running __getattr__
三. 定制自己的数据类型
包装
对已有的类型具有的功能进行扩展
class List(list):
def append(self, p_object):
if not isinstance(p_object, str):
raise TypeError('must be str')
super().append(p_object)
@property
def mid(self): # 增加属性
index = len(self) // 2
return self[index]
l = List()
l.append('oo')
l.append('jj')
l.insert(0, 'ii')
print(l)
print(l.mid)
授权
授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。
实现授权的关键点就是覆盖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):
print('running write operation')
t = time.strftime('%Y-%m-%d %X')
self.file.write('[%s] %s' % (t, line))
def __getattr__(self, item):
return getattr(self.file, item)
f = FileHandle('a.txt', 'w+')
f.write('777') # 通过授权实现执行write函数时,为所写内容添加时间
f.seek(0)
print(f.read())