反射及attr使用

反射及attr使用

返回首页

isinstance(obj,cls):检查是否obj是否是类cls的对象。

class Foo(object):
    pass

obj = Foo()
isinstance(obj,Foo)

issubclass(sub,super):检查sub类是否是super类的派生类。

class Foo(object):
    pass
class Bar(Foo):
    pass

issubclass(Bar,Foo)

反射

反射是指程序可以访问、检测和修改它本身状态或行为的一种能力,也叫自省。

在python面向对象中的反射,通过字符串的形式操作对象相关的属性,python中的一切事物都是对象(都可以使用反射)。

四个可以实现自省的函数:这四个函数适用于类和对象(一切皆为对象,类本身也是一个对象)

四个函数分别是:hasattr、getattr、setattr、delattr。

 

attr方法

hasattr:判断是否有要查询的属性的名字。

class People:
    country='China'
    def __init__(self,name):
        self.name=name
    # def walk(self):
    #     print('%s is walking' %self.name)
p=People('egon')
# People.country  #类.数据属性
# print(People.__dict__)
# print(p.name) #通过实例化.函数属性的方式,调用name函数属性。
# print(p.__dict__)

#### 反射是通过字符串来访问到country属性
#### hasattr
print('name' in p.__dict__)
print(hasattr(p,'name'))
print(hasattr(p,'name1213'))
print(hasattr(p,'country')) #p.country
print(hasattr(People,'country')) #People.country
print(hasattr(People,'__init__')) #People.__init__

getattr:拿到要查询的属性的结果,并返回。getattr需要返回值。

class People:
    country='China'
    def __init__(self,name):
        self.name=name
    def walk(self):
        print('%s is walking' %self.name)

##### getattr
p=People('egon')
res=getattr(p,'country') #res=p.country
print(res)

f=getattr(p,'walk') #t=p.walk
print(f)

f1=getattr(People,'walk')
print(f1)

f() #f()是walk的绑定方法,不需要传值。
f1(p)  #f1是一个函数,所以要传值。所以把p传进去。

print(getattr(p,'country','这个属性确实不存在'))  #如果有country,那么'这个属性确实不存在'不打印。
print(getattr(p,'xxxxxxxx','这个属性确实不存在'))

if hasattr(p,'walk'):
    func=getattr(p,'walk')
    func()

setattr:设置

class People:
    country='China'
    def __init__(self,name):
        self.name=name
    def walk(self):
        print('%s is walking' %self.name)

##### setattr
p=People('egon')
p.sex='male'
print(p.sex)
print(p.__dict__)
setattr(p,'age',18)
print(p.__dict__)
print(p.age)
print(getattr(p,'age'))

delattr :删除

class People:
    country='China'
    def __init__(self,name):
        self.name=name
    def walk(self):
        print('%s is walking' %self.name)

###### delattr
p=People('egon')
print(p.__dict__)
del p.name
print(p.__dict__)
print(p.__dict__)
delattr(p,'name')
print(p.__dict__)

 hasattr和getattr的应用:

import sys
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:
    dic_key = func_dic.keys()
    print(list(dic_key))
    cmd=input('>>:').strip()
    if not cmd:continue
    if cmd in func_dic:   #hasattr()
        func=func_dic.get(cmd)   #func=getattr()
        func()

#####用反射实现
this_module=sys.modules[__name__]

while True:
    dic_key = func_dic.keys()
    print(list(dic_key))
    cmd=input('>>:').strip()
    if not cmd:continue
    if hasattr(this_module,cmd):
        func=getattr(this_module,cmd)
        func()

用反射的好处:

一、实现可插拔机制。

有两个程序员,一个jack,一个george,jack在写程序的时候需要用到george所写的类,但是george去跟女朋友度蜜月去了,还没有完成他写的类,jack想到了反射,使用了反射机制,jack可以继续完成自己的代码,等george度蜜月回来后再继续完成类的定义并且去实现jack想要的功能。

反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用。这其实是一种“后期绑定”,即可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能。

george还没实现全部功能:client端

class FtpClient:
    "ftp客户端,但是还没有实现具体的功能"
    def __init__(self,addr):
        print("正在连接服务器[%s]" %addr)
        self.addr = addr

    def test(self):
        print("test")

    def get(self):
        print("get----》")

不影响jack的代码编写:server端

#from module import FtpClient
f1=FtpClient("192,168,1,1")
if hasattr(f1,"get")
    func_get = getattr(f1,"get")
    func_get()
else:
    print("----》不存在此方法")
    print("处理其他的逻辑")

二、动态导入模块(基于反射当前模块成员)

importlib的使用,通过字符串导入模块:

# m=input("请输入你要导入的模块:")
# m1=__import__(m)
# print(m1)
# print(m1.time())

#推荐使用方法
import importlib
t=importlib.import_module('time')
print(t.time())

__setattr__:在为对象设置属性的时候,就会被触发运行。

__delattr__:在del的时候,用pop进行删除 

#####__setattr__,__getattr__,__delattr__,
class Foo:
    def __init__(self,x):
        self.name=x
    #
    def __setattr__(self, key, value):  #为对象设置属性时,会触发setattr的运行
        if not isinstance(value,str):   #对value的数据类型限制
            raise TypeError('must be str')
        print('----setattr---key:%s,value:%s' %(key,value))
        # print(type(key))
        # print(type(value))
        # self.key=value
        # setattr(self,key_str,value) #self.key_attribute=value
        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)

f1=Foo('egon') #f1.name='egon'
f1.age="18"
print(f1.__dict__)
print(f1.name)
print(f1.age)
print(f1.__dict__)
# del f1.age
# print(f1.__dict__)
# print(f1.age)

__getattr__:获取一个指令,当获取的属性不存在的时候,才会触发__getattr__。

class Foo:
    def __init__(self,x):
        self.name=x

    #属性不存在的情况下才会触发
    def __getattr__(self, item):
        print('getattr-->%s %s' %(item,type(item)))

f=Foo('egon')
# print(f.name)
print(f.xxxxxxx)

定制自己的数据类型:也叫二次加工标准类型。

基于继承的原理,来定制自己的数据类型(继承标准类型)

例如:用List定义自己的类型,继承list类,使其在append操作的时候,只能append数字int类型以及insert数字int类型。

class List(list): #List类继承list类的方法。
    def append(self, p_object):  #定义append方法,已覆盖list的append,p_object是List的append的值
        print('--->',p_object)  #打印的p_object是即将要被append进List的数据,但是这是打印List列表,不会看到p_object,因为还没有被写进List。
        if not isinstance(p_object,int):  #加类型判断,如不是int类型,返回异常。
            raise TypeError('must be int')
        super().append(p_object) #用super方法调用父类的list的append功能。将p_object写进List。
    def insert(self, index, p_object):  #对插入操作也可以更改
        if not isinstance(p_object,int):
            raise TypeError('must be int')
        super().insert(index,p_object)

l=List([1,2,3])
print(l)
l.append(4)
print(l)
l.append('5')
print(l)
l.insert(0,-1)
print(l)
l.insert(0,'-1123123213')
print(l)

不用继承实现文件读写操作的函数功能:open

不能用继承,来实现open函数的功能
f=open('a.txt','w')
print(f)
f.write('1111111')

授权的方式实现定制自己的数据类型:

import time
class Open:  #定义open类
    def __init__(self,filepath,m='r',encode='utf-8'): #init要默认生成两个参数,一个是文件路径,一个是文件读取方式。
        self.x=open(filepath,mode=m,encoding=encode)  #在init里用open,这样在Open类中,没有继承open函数。并且这个x.open才是真正被用到的
        self.filepath=filepath  #文件路径
        self.mode=m   #文件模式
        self.encoding=encode

    def write(self,line): #文件句柄的.write操作,
        print('f自己的write',line)   #这里并没有完成真正的write操作。
        t=time.strftime('%Y-%m-%d %X') #时间,记录写入的时间。
        print(t)
        self.x.write('%s %s' %(t,line)) #这里用self.x.write才是真正的完成write操作。

    def __getattr__(self,item): #用getattr获取init里x.open的各种方法,当Open类中没有read方法的时候,可以用getattr的方式获取到read的方法。
        # print('=------>',item,type(item))   #用item解决出现异常的现象,这样写不会出现异常
        return getattr(self.x,item)  #getattr通过字符串去对象里面找数据

f=Open('b.txt','w')
print(f)
f.write('111111\n')
f.write('111111\n')
f.write('111111\n')

f=Open('b.txt','r+')
# print(f.write)
print(f.read)

res=f.read() #self.x.read()
print(res)

print('=-=====>',f.read())
f.seek(0)
print(f.read())
# f.flush()
# f.close()

 

-------- END --------

posted @ 2021-03-29 20:39  王先生是胖子  阅读(83)  评论(0编辑  收藏  举报