反射
存在:hasatter(p,'name')
获得:getattr
设置:setattr
小结练习:
反射的用途
反射实现可插拔机制
__setattr/delattr/getattr__
定制自己的数据类型
写一个自己的open
二次加工标准类型list
补充一点__getattribute__
存在:hasatter(p,'name')
获得:getattr
设置:setattr
小结练习:
反射的用途
反射实现可插拔机制
__setattr/delattr/getattr__
定制自己的数据类型
写一个自己的open
二次加工标准类型list
补充一点__getattribute__
反射
自省:程序能够访问,检测和修改他本身的状态或者行为的能力
通过字符串的形式操作对象相关属性。
class people:
country = 'China'
def __init__(self,name):
self.name = name
p = people('scott')
people.country
print(people.__dict__)
存在:hasatter(p,'name')
p这个对象下,有没有‘name’这个属性
其实就是
print('name' in p.__dict__)
返回一个bool值
获得:getattr
p这个对象下,调用country参数
gatattr(p,'country')
等同于
p.country
def getattr(object, name, default=None): # known special case of getattr
"""
getattr(object, name[, default]) -> value
Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
When a default argument is given, it is returned when the attribute doesn't
exist; without it, an exception is raised in that case.
"""
pass
设置:setattr
setattr(p,'country','China')
等同于
p.country = 'China'
提问:
>>> l = [1,2,4,5,8]
>>> setattr(l,'append','China')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object attribute 'append' is read-only
小结练习:
class People:#定义一个类
def __init__(self,name):
self.name = name#提供一个绑定参数
p1 =People('scott')#实例化p1
p2 =People('jerry')#实例化p2
#给p1对象添加一个‘country’属性,值为‘China’
setattr(p1,'country','China')
#使用getattr获取这个属性并且打印
print(getattr(p1,'country'))
#以上那个country参数,是我添加给对象p1的,查看p2是否也获得了这个参数?-----并没有,这个参数单独被加在p1这个对象中
print(hasattr(p2,'country'))
# 使用delattr删除刚才添加的country参数
delattr(p1,'country')
#检查
hasattr(p1,'country')
#定义一个函数func
def func(self):
print(self.name,' like python')
#利用lambda给p1对象传入一个work方法
setattr(p1,'work',lambda self: (self.name,'like python') )
#给p1传入func方法
setattr(p1,'work2',func )
#目前两个work方法均是针对p1传值的,但是在下方实例化p1的work2方法为h,并且对两个对象进行work2方法,发现两个对象均可以使用
#设置setattr可以将一个函数或者参数指向添加给某个对象的类
#虽然在设置中,设置的P1但是其实和p1同类的实例均可以调用
print(hasattr(p1,'work'))
g = getattr(p1,'work')
h = getattr(p1,'work2')
print(g(p1))
h(p1)
h(p2)
反射的用途
反射当前模块的属性
import sys
#导入系统模块
x = 1111
class foo:
pass
def s1():
print('s1')
def s2():
print('s2')
this_module = sys.modyles[__name__]
#将当前写的程序作为一个模块“this_module”
def add():
print('add')
def change():
print('change')
def search():
print('search')
def delete():
print('delete')
func_dic = {
'add':add
'change':change
'search':search
'delete':delete
}
- 方法一(常规)
while True:
cmd = input('>>:')
if not cmd:continu
if cmd in func_dic: #hasattr()
func= func_dic.get(cmd) #gatattr()
func()
- 方法二(利用反射实现)
this_module = sys.modyles[__name__]
#将以上程序归为一个模块,命名为this_module
while True:
cmd = input('>>>').strip()
if not cmd:continu
if hasatter(this_module,cmd):
func = getattr(this_module,cmd)
func()
反射实现可插拔机制
- server
from ftp_1 import FtpClient
#从FIP_1中载入FtpClient模块
f1 = FtpClient('192.168.1.1')
#实例化
if hasattr(f1,'get'):
#查看能不能从对象中获取一个‘get’函数
func_get = getattr(f1,'get')
func_get()#如果能获取就运行
else:
#如果没有就打出标志位
print('---------->')
在上述程序中,如果在FtpClient文件中没有定义一个get函数。并不会影响上述程序执行。但是如果FtpClient文件补全了了这个get函数,上述文件并不需要修改,就能正常实现功能
- ftp module
#提供一个FtpClient类
class FtpClient:
def __init__(self,addr):
print('lianjie [%s]'%addr)
self.addr = addr
通过字符串导入模块
m = input('module:')
m1 = __import__(m)
print(m1)
print(m1.time())
推荐使用以下方法
import importlib
t = importlib.import_module('time')
print(t.time())
__setattr/delattr/getattr__
下面这段代码,串讲一些之前提到的setattr、delattr、getattr,并且介绍__setattr/delattr/getattr__
授权:授权是包装的一个特性,包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其他的保持原样。授权的过程,即使所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性
实现授权的关键点就是覆盖__getattr__方法
class Foo:
def __init__(self,name):
self.name = name
def __setattr__(self,key,value):
print('----setattr----'key,value)
#由于传入的key和value都是字符串,不能直接跟在self后面
#self.key = value
#setattr(self,key,value)#同上
#在当前函数中设置这个赋值(因为重写了__setattr__,所有的赋值操作都会指向这个函数运行),就相当于把这个函数变成一个无限递归。
#正确的方法应该是,直接操作__dict__
self.__dict__[key] = value
def __delattr__(self,item):
print('delattr:%s'%item)
print(type(item))
# delattr(self,item)
# del self.item
self.__dict__.pop(item)
#原理同上,为了防止递归和字符串类型干扰,应该直接操作__dict__
def __getattr__(self,item);
print('get------>%s %s'%(item,type(item)))
f = Foo('scott')
print(f.name)
#当一个属性存在的时候,正常寻找self.name
print(f.xxxxx)
#当属性不存在的时候,才触发__geattr__
f1 = Foo('egon')
f1.age = 18
print(f1.__dict__)
字典为空,之前的两次传入调用参数,都直接进入了__setattr__
定制自己的数据类型
写一个类,继承原来的list类
class List(list):
def append(self,p_object):
if not isinstance(p_object,int):
raise TypeError('str')
super().append(p_object)
写一个自己的open
由于open是一个函数,所以不能直接继承
import time
class Open:
def __init__(self,filepath,m = 'r',encode = 'utf8'):
self.x= open(filepath,mode = m,encoding = 'utf8')
#以上self.x就是一个文件句柄,之后需要原文件操作类赋予的动作均使用这个句柄来进行。
self.mode = m
self.encoding = encode
def write(self,line):
print('time',line)
self.x.write(time.strftime('%Y-%m-%d %X'),line)
#授权得分
def __getattr__(self,item):
print('--->',item,type(item))
getattr(self.x,item)
#在当前类找不到某个方法的时候,因为self.x是一个可以调用各种文件操作的句柄,所以使用getattr方法,来获得这些方法,并且在上方提示。
#有了这个函数定义之后,就可以在f中使用各个文件操作方式。
f =Open('b.txt','w+')
print(f)
f.write('111111111111')
print(f.read())
f.seek(0)
二次加工标准类型list
要求使用授权的方式:
'''
作业:
基于授权定制自己的列表类型,要求定制的自己的__init__方法,
定制自己的append:只能向列表加入字符串类型的值
定制显示列表中间那个值的属性(提示:property)
其余方法都使用list默认的(提示:__getattr__加反射)
'''
class List:
def __init__(self,LOBJECT):
#将self.x定义为list类包装过的传入参数LOBJECT,以此来获得list的一些方法
self.x = list(LOBJECT)
#重新定义append方法,使所有添加进来的参数均转换成str数据类型
def append(self,value):
print('后添加的元素都是str格式!')
if not isinstance(value,str):
self.x.append(str(value))
# raise TypeError('ERROR')
else:
self.x.append(value)
#特征化一个函数,这个函数会返回一个列表的中间值,如果这个列表的元素数量为偶数,就返回中间两个值。
@property
def mid_list(self):
len_th =len(self.x)
if len_th%2==0:
f1 = self.x[(len_th//2)]
f2 = self.x[(len_th//2)-1]
return f1,f2
else:
return self.x[len_th // 2]
#授权self.x获得其他没有定义的关于list的函数,因为传入的对象为self.x,它属于list类。
def __getattr__(self, item):
getattr(self.x,item)
#为了让List对象在打印的时候也和list对象一样,一旦打印就能获得将传入数据类型变为list的能力,在这里使用__str__,使得每次传入的参数返回出来都是list
def __str__(self):
return str(self.x)
y = (4,5,7,8,6)
k = List((1,2,4,5,7))
l = List([1,2,3,4,5,6])
# print(l)
print(k)
print(List(y))
# l.append(12)
print(k.mid_list)
补充一点__getattribute__
#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
class Foo:
def __init__(self,x):
self.x=x
def __getattr__(self, item):
print('执行的是我')
# return self.__dict__[item]
def __getattribute__(self, item):
print('不管是否存在,我都会执行')
raise AttributeError('哈哈')
f1=Foo(10)
f1.x
f1.xxxxxx
#当__getattribute__与__getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程中抛出异常AttributeError