反射

一.反射

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

1 class Foo(object):
2     pass
3  
4 obj = Foo()
5  
6 isinstance(obj, Foo)

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

 1 class Bar():
 2     pass
 3 class Foo(Bar):
 4     pass
 5 obj=Foo()
 6 print(Foo.__bases__)   #判断是不是继承类
 7 print(issubclass(Foo,Bar))
 8 
 9 
10 
11 
12 (<class '__main__.Bar'>,)
13 True

1.什么是反射

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

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

hasattr(object,name)

  1.文件直接运行,把一个文件当成脚本运行

  2.当成模块导入

 1 class People:
 2     country='China'
 3     def __init__(self,name):
 4         self.name=name
 5 
 6 p=People('egon')
 7 print(p.__dict__)
 8 People.country    #调的不是字符串
 9 #hasattr
10 print('name' in p.__dict__)
11 print(hasattr(p,'name'))
12 print(hasattr(p,'country'))   #p.country
13 print(hasattr(People,'country'))  #People.country
14 print(hasattr(People,'__init__')) #People.__init__
15 
16 
17 {'name': 'egon'}
18 True
19 True
20 True
21 True
22 True

getattr(object,name,default=None)

 1 class People:
 2     country='China'
 3     def __init__(self,name):
 4         self.name=name
 5     def walk(self):
 6         print('%s is walking' %self.name)
 7 
 8 p=People('egon')
 9 
10 
11 #getattr
12 res=getattr(p,'country')  #res=p.country
13 print(res)
14 
15 f=getattr(p,'walk')  #t=p.walk
16 print(f)
17 
18 f1=getattr(People,'walk')  #类的函数属性
19 print(f1)
20 
21 f()   #绑定方法第一个参数不用传
22 f1(p)  #函数不会自动传值
23 
24 China
25 <bound method People.walk of <__main__.People object at 0x00000000004D1978>>
26 <function People.walk at 0x00000000004CE2F0>
27 egon is walking
28 egon is walking
 1 print(getattr(p,'xxxx','这个属性确实不存在'))  #保证程序不会抛出异常
 2 #或者是用下面这个
 3 
 4 if hasattr(p,'walk'):
 5     func=getattr(p,'walk')
 6     func()
 7 print('=======>')
 8 
 9 
10 
11 这个属性确实不存在
12 egon is walking
13 =======>
14 =======>

setattr(x,y,z)

 1 p.sex='male'
 2 print(p.sex)
 3 print(p.__dict__)
 4 setattr(p,'age',18)
 5 print(p.__dict__)
 6 print(p.age)
 7 print(getattr(p,'age'))
 8 
 9 
10 
11 
12 male
13 {'sex': 'male', 'name': 'egon'}
14 {'sex': 'male', 'name': 'egon', 'age': 18}
15 18
16 18

delattr(x,y)

 1 # print(p.__dict__)
 2 # del p.name
 3 # print(p.__dict__)
 4 print(p.__dict__)
 5 delattr(p,'name')
 6 print(p.__dict__)
 7 
 8 
 9 
10 
11 {'name': 'egon'}
12 {}

3.反射当前模块的属性  

this_module=sys.modules[__name__]

import sys

x=11
class Foo:
    pass
def s1():
    print('s1')

def s2():
    print('s2')

this_module = sys.modules[__name__]    #获取当前模块
print(this_module)

print(hasattr(this_module,'s1'))
print(getattr(this_module,'s2'))
print(this_module.s2)
print(this_module.s1)


<module '__main__' from 路径
True
<function s2 at 0x00000000006BE2F0>
<function s2 at 0x00000000006BE2F0>
<function s1 at 0x00000000006BE268>

4.反射的用途:

1.把字符串映射成可执行过程

2.实现可插拔机制

1 while True:
2     cmd=input('>>:').strip()
3     if not cmd:continue
4     # if cmd in func_dic:
5     #     func=func_dic.get(cmd) #hasattr
6     #     func()                 #func=getattr()
7     if hasattr(this_module,cmd):
8         func=getattr(this_module,cmd)
9         func()
1 class FtpClient:
2     'ftp客户端,但是还没有实现具体的功能'
3     def __init__(self,addr):
4         print('正在连接服务器[%s]' %addr)
5         self.addr=addr
 1 import ftpclient
 2 #from module import FtpClient
 3 f1=ftpclient.FtpClient('192.168.1.1')
 4 if hasattr(f1,'get'):   #有木有get方法
 5     func_get=getattr(f1,'get')
 6     func_get()
 7 else:
 8     print('---->不存在此方法')
 9     print('处理其他的逻辑')
10 # print(ftpclient)
11 # print(ftpclient.FtpClient)
12 
13 
14 
15 
16 正在连接服务器[192.168.1.1]
17 ---->不存在此方法
18 处理其他的逻辑

通过字符串导入模块

 1 m=input('请输入你要导入的模块:')
 2 m1=__import__(m)
 3 print(m1)
 4 print(m1.time())
 5 
 6 #推荐使用方法
 7 import importlib
 8 t=importlib.import_module('time')
 9 print(t.time())
10 
11 
12 
13 请输入你要导入的模块:time
14 <module 'time' (built-in)>
15 1493021033.3454628

手动加上类型限制,弥补python没有类型限制的不足。

 1 class Foo:
 2     def __init__(self,name):
 3         self.name=name
 4 
 5     def __setattr__(self,key,value):  #都是把属性加到字典里的,递归超过最大限制
 6         if not isinstance(value,str):
 7             raise TypeError('must be str')
 8         # print('---setattr---key:%s,value:%s' %(key,value))
 9         #setattr(self,key,value)  #self.key=value 递归了,一直再设置属性 #都是把属性加到字典里的,递归超过最大限制
10         self.__dict__[key]=value  #使用它
11 
12     def __delattr__(self, item):
13         print('---> from delattr')
14         self.__dict__.pop(item)
15 
16 f1=Foo('egon')
17 f1.age='18'
18 print(f1.name)
19 print(f1.age)
20 print(f1.__dict__)  ## 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
21 
22 f1.__dict__['a']=3
23 del f1.age
  print(f1.__dict__) ##字典里还有age

 1 class Foo:
 2     def __init__(self,x):
 3         self.name=x
 4     #属性不存在的情况下才会触发
 5     def __getattr__(self, item):
 6         print('getattr-->%s %s' %(item,type(item)))
 7 
 8 f=Foo('egon')
 9 print(f.xxx)
10 
11 
12 
13 getattr-->xxx <class 'str'>
14 None     #返回None

5.二次加工标准类型

定制自己的数据类型

定制列表里只加数字

 1 class List(list):    ##继承内置的数据类型
 2     def append(self, p_object):
 3         if not isinstance(p_object,int):
 4             raise TypeError('must be int')
      #self.append(p_object) 作为对比,这个不对的
5 super().append(p_object) #完成真正的append 6 l=List([1,2,3]) 7 print(l) 8 l.append(4) 9 print(l) 10 11 l.insert(0,-1) 12 l.insert(0,'123') 13 print(l) 14 15 16 [1, 2, 3] 17 [1, 2, 3, 4] 18 ['123', -1, 1, 2, 3, 4]

规范提示数据类型:

 1 def test(x:int,y:int)->int:
 2     return x+y
 3 print(test.__annotations__)
 4 
 5 print(test(1,2))
 6 # print(test(1,'3'))
 7 
 8 
 9 
10 
11 {'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}
12 3

1.使用继承的原理二次加工

 1 class List(list):
 2     def append(self, p_object):
 3         if not isinstance(p_object,int):
 4             raise TypeError('must be int')
 5         #self.append(p_object)
 6         super().append(p_object)
 7     # def insert(self, index, p_object):
 8     #     if not isinstance(p_object,int):
 9     #         raise TypeError('must be int')
10     #     #self.append(p_object)
11     #     super().insert(index,p_object)
12 l=List([1,2,3])
13 print(l)
14 l.append(4)
15 # print(l)
16 print(l)
17 l.insert(0,-1)
18 print(l)
19 # l.insert(0,'123')
20 # print(l)
21 
22 
23 [1, 2, 3]
24 [1, 2, 3, 4]
25 [-1, 1, 2, 3, 4]

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

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

实现授权的关键点就是覆盖__getattr__方法

 1 #不能用继承,来实现open函数的功能
 2 # f=open('a.txt','w')
 3 # print(f)
 4 # f.write('111')
 5 import time
 6 class Open:
 7     def __init__(self,filepath,m='r',encode='utf-8'):
 8         self.x=open(filepath,mode=m,encoding=encode)
 9         self.filepath=filepath
10         self.mode=m
11         self.encoding=encode
12     def write(self,line):
13         print('f自己的write',line)
14         t=time.strftime('%Y-%m-%d %X')
15         self.x.write('%s %s'%(t,line))
16 
17 f=Open('b.txt','w')
18 print(f)
19 f.write('1111
')
20 f.write('11111
')
21 f.write('11111
')
22 f.write('11111
')
import time
class Open:
    def __init__(self,filepath,m='r',encode='utf-8'):
        self.x=open(filepath,mode=m,encoding=encode)
        self.filepath=filepath
        self.mode=m
        self.encoding=encode
    def write(self,line):
        print('f自己的write',line)
        t=time.strftime('%Y-%m-%d %X')
        self.x.write('%s %s'%(t,line))

    def __getattr__(self, item):
        print('=------>',item,type(item))
        return (getattr(self.x,item))

# f=Open('b.txt','w')
# print(f)
# f.write('1111
')
# f.write('11111
')
# f.write('11111
')
# f.write('11111
')

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

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


=------> read <class 'str'>
<built-in method read of _io.TextIOWrapper object at 0x00000000008EEA68>
=------> read <class 'str'>
2017-04-24 17:49:50 1111
2017-04-24 17:49:50 11111
2017-04-24 17:49:50 11111
2017-04-24 17:49:50 11111

=------> read <class 'str'>
=-==> 
=------> seek <class 'str'>
=------> read <class 'str'>
2017-04-24 17:49:50 1111
2017-04-24 17:49:50 11111
2017-04-24 17:49:50 11111
2017-04-24 17:49:50 11111

模拟open()打开文件

import time
class Open():
    def __init__(self,filepath):
        self.path=filepath
        self.x=open(filepath,'w+')
    def write(self,value):
        t=time.strftime('%Y-%m-%d')
        self.x.write(t+value)
    def __getattr__(self, item):
        if hasattr(self.x,item):
            return getattr(self.x,item)

f=Open('a.txt')
f.read()
f.seek(0)
f.flush()
原文地址:https://www.cnblogs.com/jiangshitong/p/6758323.html