面向对象进阶---反射

一 isinstance(obj,cls)和issubclass(sub,super)

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

class Foo:
    pass
obj=Foo()
print(isinstance(obj,Foo))

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

class Foo:
    pass
class Bar(Foo):
    pass

print(Bar.__dict__)
print(issubclass(Bar,Foo))

二 反射
1.概念:主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。
2.python面向对象中的反射:通过字符串的形式操作对象相关的属性。
 python中的一切事物都是对象(都可以使用反射)
3.四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象) 

1.hasattr(object,name)
2.getattr(object, name, default=None)
3.setattr(x, y, v) 
4.delattr(x, y)
 1 class People:
 2     country="China"
 3     def __init__(self,name):
 4         self.name=name
 5     def walk(self):
 6         print("-------------")
 7 
 8 p=People("fei")
 9 #-----------hasattr用法-->检测是否含有某属性
10 # print(People.__dict__)
11 # print(p.__dict__)
12 # print("name"in p.__dict__)
13 # print("country"in People.__dict__)
14 print(hasattr(People,"country"))
15 print(hasattr(p,"country"))
16 print(hasattr(People,"walk"))
17 print(hasattr(p,"walk"))
18 print(hasattr(People,"name"))
19 
20 #------------getattr的用法-->获取属性
21 res=getattr(People,"country")
22 res=People.country
23 print(res)
24 print(p.xxx)  #报错
25 print(getattr(p,"xxx","该参数不存在"))#自己添加报错信息,不填系统报错
26 if hasattr(p,"walk"):
27     func=getattr(p,"walk")
28     func()
29 
30 print("==============") #利用这种反射方法可以扩展新的程序
31 
32 #-------------setattr用法-->设置及修改属性
33 # p.sex="male" #给对象添加新的属性
34 # print(p.sex)
35 # print(p.__dict__)
36 
37 # setattr(p,"sex","famale")
38 # print(p.sex)
39 # print(p.__dict__)   #修改增加
40 # setattr(p,"age",18)
41 # print(p.__dict__)
42 # print(getattr(p,"age"))
43 
44 #-----------delattr的用法-->删除属性
45 print(p.__dict__)
46 delattr(p,"name")
47 print(p.__dict__)
使用方法

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

 import sys #导入一个模块名
 def s1():
     print 's1'
 def s2():
     print 's2'
test
 1 #一个完整的py文件就是一个模块
 2 import test
 3 
 4 print(test)#显示这个模块的名字,模块路径
 5  #调用模块的属性就在模块名加点就可以,一切皆文件,模块也是文件,so~
 6 print(test.x) 
 7 print(test.s1)
 8 print(test.s2)
 9 
10 test1中导入test这个模块
test1中导入test这个模块

  反射自己当前模块成员(不要疑问,先记住)

import sys #先导入一个sys模块

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)#类似方法

**补充:通过字符串导入其他模块

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())

三 为什么用反射?反射的好处是什么?

  好处一:实现可插拔机制

1 class Ftp_Client:
2     def __init__(self,addr):
3         print("正在连接服务器%s"%(addr))
4         self.addr=addr
5     def test(self):
6         print("----test----")
ftp客户端
 1 import ftp客户端
 2 f1=ftp客户端.Ftp_Client("192.168.3.3")
 3 print(hasattr(f1,"test"))
 4 print(hasattr(f1,"get"))
 5 if hasattr(f1,"get"):
 6     func_get=getattr(f1,"get")
 7     func_get()
 8 else:
 9     print("对方还没写完进了看守所,先写自己的程序吧。")
10     #此处可以先写自己的程序,无需等待客服端的代码
ftp服务端

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

四 attr系列 (__setattr__,__delattr__,__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
三者的使用方法

五 二次加工标准类型(包装)-->定制自己的数据类型

包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)

 1 #基于继承的原理,来定制自己的数据类型(继承标准类型)
 2 class List(list):
 3     def append(self, p_object):
 4         if not isinstance(p_object,int):
 5             raise TypeError("必须输入一个字整数类型")
 6         else:
 7             super().append(p_object)
 8     def insert(self, index, p_object):
 9         if not isinstance(p_object,int):
10             raise TypeError("必须整数类型")
11         else:
12             super().insert(index,p_object)
13 
14 l=List([1,2,3])
15 print(l)
16 l.append(5555)
17 print(l)
18 l.append("dsa")
19 print(l)
20 l.insert(1,333)
21 print(l)
22 l.insert(1,"asd")
23 print(l)
二次加工标准类型(基于继承实现)

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

  *附加一个python中查看当前时间的方法

import time
res=time.strftime("%Y-%m-%d %X")
print(res)     #输出为----->  2017-04-24 20:17:21
 1 #不能用继承,来实现open函数的功能(因为类继承不了函数)
 2 #授权的方式实现定制自己的数据类型
 3 import time
 4 class Open:
 5     def __init__(self,file_path,m="r",encode="utf8"):
 6         self.file_path=file_path
 7         self.mode=m
 8         self.encoding=encode
 9         self.x=open(file_path,mode=m,encoding=encode)
10     def write(self,line):
11         t=time.strftime("%Y-%m-%d %X")
12         self.x.write("%s---->%s"%(t,line))
13 
14     def __getattr__(self, item):
15         # print("--------",item)
16         return getattr(self.x,item)
17 # f=Open("a.txt","a")
18 # # print(f)
19 # f.write("open函数说你侵权...\n")
20 # f.write("open函数说你山寨...\n")
21 f=Open("a.txt","r")
22 # print(f.read)
23 res=f.read()
24 print(res)
25 f.seek(0)
26 print("seek调整后可以重新读",f.read())
授权的使用方法

 

posted @ 2017-04-24 15:26  im777  阅读(173)  评论(0编辑  收藏  举报