Python之面向对象反射

Python之面向对象反射

   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 类的派生类

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

  反射:

1 什么是反射

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

 

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

四个可以实现自省的函数

下列方法适用于类和对象(一切皆对象,类本身也是一个对象)

 

hasattr(object,name)
判断object中有没有一个name字符串对应的方法或属性
1 def getattr(object, name, default=None): # known special case of getattr
2     """
3     getattr(object, name[, default]) -> value
4 
5     Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
6     When a default argument is given, it is returned when the attribute doesn't
7     exist; without it, an exception is raised in that case.
8     """
9     pass
getattr(object, name, default=None)
1 def setattr(x, y, v): # real signature unknown; restored from __doc__
2     """
3     Sets the named attribute on the given object to the specified value.
4 
5     setattr(x, 'y', v) is equivalent to ``x.y = v''
6     """
7     pass
setattr(x, y, v)
1 def delattr(x, y): # real signature unknown; restored from __doc__
2     """
3     Deletes the named attribute from the given object.
4 
5     delattr(x, 'y') is equivalent to ``del x.y''
6     """
7     pass
delattr(x, y)
 1 class BlackMedium:
 2     feature='Ugly'
 3     def __init__(self,name,addr):
 4         self.name=name
 5         self.addr=addr
 6 
 7     def sell_house(self):
 8         print('%s 黑中介卖房子啦,傻逼才买呢,但是谁能证明自己不傻逼' %self.name)
 9     def rent_house(self):
10         print('%s 黑中介租房子啦,傻逼才租呢' %self.name)
11 
12 b1=BlackMedium('万成置地','回龙观天露园')
13 
14 #检测是否含有某属性
15 print(hasattr(b1,'name'))
16 print(hasattr(b1,'sell_house'))
17 
18 #获取属性
19 n=getattr(b1,'name')
20 print(n)
21 func=getattr(b1,'rent_house')
22 func()
23 
24 # getattr(b1,'aaaaaaaa') #报错
25 print(getattr(b1,'aaaaaaaa','不存在啊'))
26 
27 #设置属性
28 setattr(b1,'sb',True)
29 setattr(b1,'show_name',lambda self:self.name+'sb')
30 print(b1.__dict__)
31 print(b1.show_name(b1))
32 
33 #删除属性
34 delattr(b1,'addr')
35 delattr(b1,'show_name')
36 delattr(b1,'show_name111')#不存在,则报错
37 
38 print(b1.__dict__)
四个方法的使用演示
 1 class Foo(object):
 2  
 3     staticField = "old boy"
 4  
 5     def __init__(self):
 6         self.name = 'wupeiqi'
 7  
 8     def func(self):
 9         return 'func'
10  
11     @staticmethod
12     def bar():
13         return 'bar'
14  
15 print getattr(Foo, 'staticField')
16 print getattr(Foo, 'func')
17 print getattr(Foo, 'bar')
类也是对象
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 import sys
 5 
 6 
 7 def s1():
 8     print 's1'
 9 
10 
11 def s2():
12     print 's2'
13 
14 
15 this_module = sys.modules[__name__]
16 
17 hasattr(this_module, 's1')
18 getattr(this_module, 's2')
反射当前模块成员

导入其他模块,利用反射查找该模块是否存在某个方法

1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3 
4 def test():
5     print('from the test')
module_test.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3  
 4 """
 5 程序目录:
 6     module_test.py
 7     index.py
 8  
 9 当前文件:
10     index.py
11 """
12 
13 import module_test as obj
14 
15 #obj.test()
16 
17 print(hasattr(obj,'test'))
18 
19 getattr(obj,'test')()

 

 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 p=People('egon')
 8 #
 9 # People.country
10 # print(People.__dict__)
11 
12 # print(p.name)
13 # print(p.__dict__)
14 
15 # p.name
16 
17 
18 #hasattr
19 # print('name' in p.__dict__)
20 # print(hasattr(p,'name'))
21 # print(hasattr(p,'name1213'))
22 
23 # print(hasattr(p,'country')) #p.country
24 # print(hasattr(People,'country')) #People.country
25 # print(hasattr(People,'__init__')) #People.__init__
26 
27 
28 #getattr
29 # res=getattr(p,'country') #res=p.country
30 # print(res)
31 #
32 # f=getattr(p,'walk') #t=p.walk
33 # print(f)
34 #
35 # f1=getattr(People,'walk')
36 # print(f1)
37 #
38 # f()
39 # f1(p)
40 
41 
42 # print(p.xxxxxxx)
43 # print(getattr(p,'xxxxxxxx','这个属性确实不存在'))
44 
45 #
46 # if hasattr(p,'walk'):
47 #     func=getattr(p,'walk')
48 #     func()
49 #
50 # print('================>')
51 # print('================>')
52 
53 
54 #setattr
55 
56 # p.sex='male'
57 # print(p.sex)
58 # print(p.__dict__)
59 
60 # setattr(p,'age',18)
61 # print(p.__dict__)
62 # print(p.age)
63 # print(getattr(p,'age'))
64 
65 
66 
67 
68 #delattr
69 # print(p.__dict__)
70 # del p.name
71 # print(p.__dict__)
72 
73 print(p.__dict__)
74 delattr(p,'name')
75 print(p.__dict__)
View Code

3 为什么用反射之反射的好处

好处一:实现可插拔机制

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

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

1 class FtpClient:
2     'ftp客户端,但是还么有实现具体的功能'
3     def __init__(self,addr):
4         print('正在连接服务器[%s]' %addr)
5         self.addr=addr
还没有实现全部功能
1 #from module import FtpClient
2 f1=FtpClient('192.168.1.1')
3 if hasattr(f1,'get'):
4     func_get=getattr(f1,'get')
5     func_get()
6 else:
7     print('---->不存在此方法')
8     print('处理其他的逻辑')
不影响lili的代码编写

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

  

  反射的用途:

    

import sys
def add():
    print('add')

def change():
    print('change')

def search():
    print('search')

def delete():
    print('delete')

this_module=sys.modules[__name__]
while True:
    cmd=input('>>:').strip()
    if not cmd:continue
    if hasattr(this_module,cmd):
        func=getattr(this_module,cmd)
        func()
    # if cmd in func_dic: #hasattr()
    #     func=func_dic.get(cmd) #func=getattr()
    #     func()


# func_dic={
#     'add':add,
#     'change':change,
#     'search':search,
#     'delete':delete
# }

# while True:
#     cmd=input('>>:').strip()
#     if not cmd:continue
#     if cmd in func_dic: #hasattr()
#         func=func_dic.get(cmd) #func=getattr()
#         func()


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


#     def walk(self):
#         print('walking......')
# f=Foo('egon')


# Foo.__dict__={'x':1,'walk':....}
# 'x' in Foo.__dict__ #hasattr(Foo,'x')
# Foo.__dict__['x'] #getattr(Foo,'x')
# print(Foo.x) #'x' in Foo.__dict__

 

  反射实现可插拔机制:

    FTP Server:

 1 import ftpclient
 2 #
 3 # print(ftpclient)
 4 # print(ftpclient.FtpClient)
 5 # obj=ftpclient.FtpClient('192.168.1.3')
 6 #
 7 # print(obj)
 8 # obj.test()
 9 
10  
11 
12 #
13 f1=ftpclient.FtpClient('192.168.1.1')
14 if hasattr(f1,'get'):
15     func=getattr(f1,'get')
16     func()
17 else:
18     print('其他逻辑')
View Code

    FTP Client:

 1 class FtpClient:
 2     'ftp客户端,但是还么有实现具体的功能'
 3     def __init__(self,addr):
 4         print('正在连接服务器[%s]' %addr)
 5         self.addr=addr
 6     def test(self):
 7         print('test')
 8 
 9     def get(self):
10         print('get------->')
View Code

 

  通过字符串导入模块:

# m=input("请输入你要导入的模块:")

# m1=__import__(m)  #官方不推荐
# print(m1)      #官方不推荐
# print(m1.time())  #官方不推荐

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

 

  attr系列:

  __getattr__、__setattr__、__delattr__

 

  setattr:为对象设置属性的时候回触发setattr的运行。

 getattr:只有在使用点调用属性且属性不存在的时候才会触发
 1 class Foo:
 2     x=1
 3     def __init__(self,y):
 4         self.y=y
 5 
 6     def __getattr__(self, item):
 7         print('----> from getattr:你找的属性不存在')
 8 
 9 
10     def __setattr__(self, key, value):
11         print('----> from setattr')
12         # self.key=value #这就无限递归了,你好好想想
13         # self.__dict__[key]=value #应该使用它
14 
15     def __delattr__(self, item):
16         print('----> from delattr')
17         # del self.item #无限递归了
18         self.__dict__.pop(item)
19 
20 #__setattr__添加/修改属性会触发它的执行
21 f1=Foo(10)
22 print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
23 f1.z=3
24 print(f1.__dict__)
25 
26 #__delattr__删除属性的时候会触发
27 f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
28 del f1.a
29 print(f1.__dict__)
30 
31 #__getattr__只有在使用点调用属性且属性不存在的时候才会触发
32 f1.xxxxxx
三者的用法演示

 

  定制自己的数据类型:    

# l=list([1,2,3])
#
# l.append(4)
# l.append('5')
# print(l)

# class List(list):
#     pass
#
# l1=List([1,2,3])
# print(l1)
# l1.append(4)
# print(l1)
# l1.append('5')
# print(l1)

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

# class List(list):
#     def append(self, p_object):
#         # print('--->',p_object)
#         if not isinstance(p_object,int):
#             raise TypeError('must be int')
#         # self.append(p_object)
#         super().append(p_object)
#     def insert(self, index, p_object):
#         if not isinstance(p_object,int):
#             raise TypeError('must be int')
#         # self.append(p_object)
#         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)
# l.insert(0,'-1123123213')
# print(l)


# def test(x:int,y:int)->int:
#     return x+y
# print(test.__annotations__)
#
# print(test(1,2))
# print(test(1,'3'))
#
# def test(x,y):
#     return x+y


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

#授权的方式实现定制自己的数据类型
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('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() 

 

  作业:

 1 #基于继承来定制自己的数据类型
 2 class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid
 3     def append(self, p_object):
 4         ' 派生自己的append:加上类型检查'
 5         if not isinstance(p_object,int):
 6             raise TypeError('must be int')
 7         super().append(p_object)
 8     #
 9     @property
10     def mid(self):
11         '新增自己的属性'
12         index=len(self)//2
13         return self[index]
14 
15 
16 # l=List([1,2,3])
17 
18 # print(l.mid)
19 
20 #基于授权来定制自己的数据类型:
21 
22 # class Open:
23 #     def __init__(self,filepath,mode,encode='utf-8'):
24 #         self.f=open(filepath,mode=mode,encoding=encode)
25 #         self.filepath=filepath
26 #         self.mode=mode
27 #         self.encoding=encode
28 
29 #     def write(self,line):
30 #         print('write')
31 #         self.f.write(line)
32 
33 #     def __getattr__(self, item):
34 #         return getattr(self.f,item)
35 
36 # # f=Open('a.txt','w')
37 # # f.write('123123123123123\n')
38 # # print(f.seek)
39 # # f.close()
40 # #
41 # # f.write('111111\n')
42 
43 
44 # f=open('b.txt','w')
45 # f.write('bbbbbb\n')
46 # f.close()
47 # print(f)
48 
49 
50 
51 # class Foo:
52 #     def test(self):
53 #         pass
54 #
55 # print(getattr(Foo,'test'))
56 #
57 # obj=Foo()
58 # print(getattr(obj,'test'))
59 
60 
61 
62 class List:
63     def __init__(self,x):
64         self.seq=list(x)
65 
66     def append(self,value):
67         if not isinstance(value,str):
68             raise TypeError('must be str')
69         self.seq.append(value)
70     @property
71     def mid(self):
72         index=len(self.seq)//2
73         return self.seq[index]
74     def __getattr__(self, item):
75         return getattr(self.seq,item)
76 
77     def __str__(self):
78         return str(self.seq)
79 
80 l=List([1,2,3])
81 
82 l.append('1')
83 
84 print(l.mid)
85 l.insert(0,123123123123123123123123123)
86 # print(l.seq)
87 
88 print(l)
89 
90 
91 obj.name='egon'
92 del obj.name
View Code

 

 

链接:详细

 

posted @ 2018-06-27 14:39  王先生是胖子  阅读(261)  评论(0编辑  收藏  举报