2017年4月24日 python 之反射

什么是反射:

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

python的反射:

由于python中一切事物都是对象,所以都可以使用反射,这种用字符串形式操作对象相关的属性。

基于类的反射:

# 基于类的反射
class People:
    country="china"
    def __init__(self,name):
        self.name=name

    def walk(self):
        print("%s walk",self.name)

h=People("ada")
# 利用布尔值返回类或对象有没有这个属性
print(hasattr(People,"country"))
print(hasattr(h,"country"))
print(hasattr(h,"walk"))

#获取类或对象的某个属性
res1=getattr(People,"country")
print(res1)
res2=getattr(h,"country")
print(res2)
res3=getattr(h,"walk")
print(res3)

#设置类或对象的某个属性并查看
setattr(h,"age",18)
print(h.__dict__)

#删除类或对象的某个属性并查看
delattr(h,"age")
print(h.__dict__)

基于模块的反射:

# 基于模块的发射
# 反射当前模块的属性

import sys

x=1111
class Foo:
    pass

def s1():
    print('s1')
def s2():
    print('s2')

this_module=sys.modules[__name__]
print(this_module)

#这句话所做的操作:遍历s1在不在this_module 的字典__dict__中
print(hasattr(this_module,'s1'))   
print(getattr(this_module,'s2'))
print(this_module.s1)
print(this_module.s2)


# import importlib
# t=importlib.import_module("time")
# print(t.time())

# 字符串导入模块,官方不推荐
# m=input("please input your module:")
# m1=__import__(m) 
# print(m1)
# print(m1.time())

 

对类的属性的操作:__getattr__,  __setattr__,  __delattr__

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

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

  #增加/修改等赋值操作触发他的运行
    def __setattr__(self, key, value):
        if not isinstance(value,str):
            raise TypeError("must be str")
        self.__dict__[key]=value
  #删除操作触发他的运行
    def __delattr__(self, item):
        self.__dict__.pop()



f=Foo("egon")
f.eat   #Foo没有eat这个属性所以,所以触发__getattr__,打印:eat <class 'str'>--->
f.age=18  #报错,因为不符合设置属性时候,我们判断的是必须是字符串,因此抛出:must be str

重新定制我们的list列表类型:使他添加,插入都必须是int.

class List(list):
    def append(self,object:str):
        if not isinstance(object,int):
            raise TypeError("must int")
        super().append(object)

    def insert(self, index: int, object):
        if not isinstance(object,int):
            raise TypeError("must int")
        super().insert(index,object)


l=List([1,2,3])
print(l)
l.append(4)
print(l)

l.insert(0,-1)
# l.insert(0,"hahahaha")  #报错,因为我们重写了增加和插入方法,非int类型插入报错,必须是int类型
print(l)

 

 

反射的好处:

(1)即插即用,类似优盘,你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能,后期绑定。

#同一文件目录下,建立FtpClient.py,只是粗略定一个客户端类,没有具体实现,服务端可以判断一下然后继续执行,客户端后面写也行

class FtpClient:
    'ftp客户端,现在并没有实现具体的功能'
    def __init__(self,addr):
        print('正在连接服务器[%s]' %addr)
        self.addr=addr
# 同一文件下建立server.py 然后引入客户端包,运行,假如没有反射机制,getattr()方法就无法判断客户端有没有get 方法
import FtpClient   #忽律解释器的红线
f1=FtpClient.FtpClient('192.168.1.1')
if hasattr(f1,'get'):
    func_get=getattr(f1,'get')
    func_get()
else:
    print('---->目前不存在此方法')
    print('先处理其他的逻辑')

 

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

# import importlib
# t=importlib.import_module("time")
# print(t.time())

#导入当前路径下包impag下的hello.py
# x=importlib.import_module("impag.hello")


# 字符串导入模块,官方不推荐
# m=input("please input your module:")
# m1=__import__(m)
# print(m1)
# print(m1.time())

 

 

二次加工标准类型:包装和授权

#包装
class
List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid def append(self, p_object): ' 派生自己的append:加上类型检查' if not isinstance(p_object,int): raise TypeError('must be int') super().append(p_object) @property def mid(self): '新增自己的属性' index=len(self)//2 return self[index] l=List([1,2,3,4]) print(l) l.append(5) print(l) # l.append('1111111') #报错,必须为int类型 print(l.mid) #其余的方法都继承list的 l.insert(0,-123) print(l) l.clear() print(l)

 


# 授权是包装的一个特性。
# 包装的过程:一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能,其它的则保持原样。
# 授权的过程:所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。


import time
class FileHandle:
    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):
        return getattr(self.file,item)

f1=FileHandle('b.txt','w+')
f1.write('时间和文本组成记录')
f1.seek(0)
print(f1.read())
f1.close()

 

posted @ 2017-04-24 16:45  Adamanter  阅读(172)  评论(0编辑  收藏  举报