Python 反射
Posted 陈彦斌
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 反射相关的知识,希望对你有一定的参考价值。
一 反射
什么是反射?
反射的概念由smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在List和面向对象方面取得了成绩。
4个可以实现反射的函数
下列方法适用于类和对象
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 # 判断object中有没有一个name字符串对应的方法或属性 6 class BlackMedium: 7 feture = ‘Ugly‘ 8 9 def __init__(self, name, addr): 10 self.name = name 11 self.addr = addr 12 13 def sell_hourse(self): 14 print(‘【%s】正在卖房子‘ % self.name) 15 16 def rent_hourse(self): 17 print(‘【%s】正在租房子‘ % self.name) 18 19 20 b1 = BlackMedium(‘alex‘, ‘雪峰路‘) # bl.name--->b1.__dic[‘name‘] 21 print(hasattr(b1, ‘name‘)) # True
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 # 判断object中有没有一个name字符串对应的方法或属性 6 class BlackMedium: 7 feture = ‘Ugly‘ 8 9 def __init__(self, name, addr): 10 self.name = name 11 self.addr = addr 12 13 def sell_hourse(self): 14 print(‘【%s】正在卖房子‘ % self.name) 15 16 def rent_hourse(self): 17 print(‘【%s】正在租房子‘ % self.name) 18 19 20 b1 = BlackMedium(‘alex‘, ‘雪峰路‘) # bl.name--->b1.__dic[‘name‘] 21 print(getattr(b1, ‘name‘)) # alex
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 # 判断object中有没有一个name字符串对应的方法或属性 6 class BlackMedium: 7 feture = ‘Ugly‘ 8 9 def __init__(self, name, addr): 10 self.name = name 11 self.addr = addr 12 13 def sell_hourse(self): 14 print(‘【%s】正在卖房子‘ % self.name) 15 16 def rent_hourse(self): 17 print(‘【%s】正在租房子‘ % self.name) 18 19 20 b1 = BlackMedium(‘alex‘, ‘雪峰路‘) # bl.name--->b1.__dic[‘name‘] 21 setattr(b1, ‘test‘, 123) 22 print(b1.test) # 123 23 print(b1.__dict__) # {‘name‘: ‘alex‘, ‘addr‘: ‘雪峰路‘, ‘test‘: 123}
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 # 判断object中有没有一个name字符串对应的方法或属性 6 class BlackMedium: 7 feture = ‘Ugly‘ 8 9 def __init__(self, name, addr): 10 self.name = name 11 self.addr = addr 12 13 def sell_hourse(self): 14 print(‘【%s】正在卖房子‘ % self.name) 15 16 def rent_hourse(self): 17 print(‘【%s】正在租房子‘ % self.name) 18 19 20 b1 = BlackMedium(‘alex‘, ‘雪峰路‘) # bl.name--->b1.__dic[‘name‘] 21 setattr(b1, ‘test‘, 123) 22 print(b1.test) # 123 23 print(b1.__dict__) # {‘name‘: ‘alex‘, ‘addr‘: ‘雪峰路‘, ‘test‘: 123} 24 delattr(b1, ‘test‘) # <==> del b1.test 25 print(b1.__dict__) # {‘name‘: ‘alex‘, ‘addr‘: ‘雪峰路‘}
反射应用示例:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 class FtpClient: 6 def __init__(self, addr): 7 print(‘正在连接Ftp‘) 8 self.addr = addr
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from Ftp_Client import FtpClient 4 5 f1 = FtpClient(‘172,16,1,10‘) 6 7 if hasattr(f1, ‘put‘): 8 func_get = getattr(f1, ‘put‘) 9 func_get() 10 else: 11 print(‘其他的逻辑‘)
动态导入模块:
1 # 示例一 2 from m1.t import test1 3 m = test1 # 获得顶级模块名 4 5 6 # 示例二 7 import importlib 8 m = importlib.import_module(‘字符串‘) # 定位到导入的那个模块
双下划线开头的attr方法
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 # 注:__getattr__ 调用一个不存在的对象会执行 5 class Foo: 6 x = 1 7 8 def __init__(self, y): 9 self.y = y 10 11 def __getattr__(self, item): 12 print(‘执行__getattr__‘) 13 14 15 f1 = Foo(10) 16 print(f1.y) # 10 17 print(f1.z) # 执行__getattr__;None
1 # 注:__delattr__ 删除操作会执行 2 class Foo: 3 x = 1 4 5 def __init__(self, y): 6 self.y = y 7 8 def __delattr__(self, item): 9 print(‘删除__delattr__‘) 10 11 12 f1 = Foo(10) 13 del f1.y # 删除__delattr__ 14 del f1.z # 删除变量不存在时,也会执行__delattr__;删除__delattr__
1 class Foo: 2 x = 1 3 4 def __init__(self, y): 5 self.y = y 6 7 def __setattr__(self, key, value): 8 print(‘执行__setattr__‘) 9 self.__dict__[key] = value 10 11 12 f1 = Foo(10) # 执行__setattr__
二 二次加工标准类型(包装)
包装:Python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 class List(list): 6 def append(self, p_object): 7 if type(p_object) is str: 8 super().append(p_object) # <==> list.append(self, p_object) 9 else: 10 print(‘添加数据类型不是字符串‘) 11 12 def show_midille(self): # 求列表中间值 13 mid_index = int(len(self) / 2) 14 return self[mid_index] 15 16 17 l1 = List(‘hello world!‘) 18 # print(l1.show_midille()) # w 19 l1.append(‘123‘) 20 print(l1) # [‘h‘, ‘e‘, ‘l‘, ‘l‘, ‘o‘, ‘ ‘, ‘w‘, ‘o‘, ‘r‘, ‘l‘, ‘d‘, ‘!‘, ‘123‘]
授权:授权是包装的一个特性,包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。
实现授权的关键点就是覆盖__getattr__方法
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import time 4 5 6 class openfile: 7 def __init__(self, filename, mode=‘r‘, encoding=‘utf-8‘): 8 # self.filename = filename 9 self.file = open(filename, mode, encoding=encoding) 10 self.mode = mode 11 self.encoding = encoding 12 13 def write(self, line): 14 t = time.strftime(‘%Y-%m-%d %X‘) 15 time.sleep(1) 16 self.file.write(‘%s %s‘ % (t, line)) 17 18 def __getattr__(self, item): 19 # print(item, type(item)) # read <class ‘str‘> 20 # self.file.read 21 return getattr(self.file, item) 22 23 24 f1 = openfile(‘a.txt‘, ‘w+‘) 25 # print(f1.file) 26 # print(f1.read) # 触发__getattr__;<built-in method read of _io.TextIOWrapper object at 0x000000C2ECCAAC18> 27 # f1.seek(1) 28 # print(f1.read()) 29 f1.write(‘cpu负载过高 ‘) 30 f1.write(‘内存剩余不足 ‘) 31 32 # a.txt内容 33 ‘‘‘ 34 2019-02-17 21:30:15 cpu负载过高 35 2019-02-17 21:30:16 内存剩余不足 36 ‘‘‘
以上是关于Python 反射的主要内容,如果未能解决你的问题,请参考以下文章