python中的反射
2021-01-24 13:16
标签:mic one port false mil span file log 需要 所谓反射是指通过字符串的方式获取对象,然后执行对象的属性或方法。在python中一切皆对象,因此我们可以对一切事物进行发射。 关于反射python为我们提供了四个方法: hasattr(object, name):name必须是字符串,如果字符串name是object对象当中的某一属性或某一方法将返回True,否则返回False。 getattr(object, name ,default=None):name必须是字符串,如果字符串name是object对象当中的某一属性或某一方法将返回对应的属性或方法,否则如果给定默认值将返回默认值,如果没指定默认值将引发AttributeError的异常。 setattr(object, name, value):可以新增或修改对象的属性,name必须是字符串,value可以是任意数据类型。如果name是object的属性将修改对应属性的值为value,如果对象不是object的属性将新增一个属性。 delattr(object, name):删除对象属性,name必须是字符串,name必须是object的属性且object对这个属性有删除的权限,否则将引发AttributeError。 下面以对对象进行反射,对类进行反射,对当前模块进行反射,对其它模块进行反射为示例来了解反射的应用。 关于getattr(object, name ,default=None)中的参数default需要注意,直接按位置参数传参即可,不要是要关键字参数进行传参,否则会报错。 看了上面的代码片段,也许你会感觉反射也不过如此,但是在有些场景反射真的很有用,下面以FTP server和FTP client为例,我之前写的小练习。 有兴趣的朋友可以看一下:https://www.cnblogs.com/caesar-id/p/12105321.html里面服务端对客户端发来的命令进行解析时就是用的反射,如果不用反射,就需要使用大量的if来解析客户端要执行哪条命令。 下面在不使用反射的情况下解析客户端发来的命令(伪代码): 上面的情况很明显的就是程序有多少功能,就需要有多少个if来对其进行判断,当某个方法发生改变或新增功能时,需要到if中添加相应的逻辑判断或者修改对应的逻辑,无论是从代码的阅读还是后期的维护都不是很方便。 下面使用反射的情况下解析客户端发来的命令: 使用反射对客户端命令解析,无论程序有多少方法,都只需上面那几行代码即可。相比通过if对命令解析反射结构更加清晰,当某个方法发生改变,或添加新的功能,只需要把所有精力都用在功能实现上即可,不需要像if那样新增逻辑或者修改对应的逻辑,易于维护。到此反射就简单介绍到这里。 python中的反射 标签:mic one port false mil span file log 需要 原文地址:https://www.cnblogs.com/caesar-id/p/12864876.htmlpython反射简介
对类进行反射
class A:
num = 10
def fun(self):
print(‘Hello World‘)
# 判断A中是否有fun属性或方法
if hasattr(A,‘fun‘):
# 获取fun方法的内存地址
f = getattr(A,‘fun‘)
# 执行A中fun的方法
f(‘‘)
# 打印结果如下
Hello World
# 给A中新增属性buf
setattr(A,‘buf‘,[1,2,3])
print(A.buf)
# 打印内容如下
[1, 2, 3]
# 删除类中属性num
delattr(A,‘num‘)
print(A.num)
# 打印结果如下
AttributeError: type object ‘A‘ has no attribute ‘num‘
对对象进行反射
class A:
num = 10
def fun(self):
print(‘Hello World‘)
obj = A()
# 判断对象obj中是否有fun方法
if hasattr(obj,‘fun‘):
# 获取对象中fun方法的内存地址
f = getattr(obj,‘fun‘)
# 执行obj中fun方法
f()
# 打印结果如下
Hello World
# 给对象obj新增属性buf
setattr(obj,‘buf‘,[1,2,3])
print(obj.buf)
# 打印结果如下
[1, 2, 3]
# 删除obj中属性buf
delattr(obj,‘buf‘)
# 删除类A的属性num
delattr(obj,‘num‘)
# 引发如下异常
delattr(obj,‘num‘)
AttributeError: num
原因:obj是类A的实例化对象,它有自己的内存空间,与类A空间互不干涉,obj仅可以访问类A的属性和方法,是不能对类A中原有的属性和方法进行修改的。
对当前模块进行发射
import sys
class A:
num = 10
def fun(self):
print(‘Hello World‘)
def f():
print(‘对当前模块进行反射‘)
# 获取当前模块
current_module = sys.modules[__name__]
# 获取当前模块下的类A
if hasattr(current_module,‘A‘):
obj_A = getattr(current_module,‘A‘)
obj_A.fun(‘‘)
# 获取当前模块下的函数f
if hasattr(current_module,‘f‘):
obj_f = getattr(current_module,‘f‘)
obj_f()
# 打印内容如下
Hello World
对当前模块进行反射
对其它模块进行反射
# 1.py对test.py进行反射
============================
# test.py中代码如下
class A:
num = 10
def fun(self):
print(‘Hello World‘)
def f():
print(‘对当前模块进行反射‘)
============================
# 1.py中代码如下
# 第一种方式
import test
# 获取test.py模块下的类A
if hasattr(test,‘A‘):
obj_A = getattr(test,‘A‘)
obj_A.fun(‘‘)
# 获取test.py模块下的函数f
if hasattr(test,‘f‘):
obj_f = getattr(test,‘f‘)
obj_f()
# 打印内容如下
Hello World
对当前模块进行反射
# 第二种方式
imp_module = __import__(‘test‘)
# 获取test.py模块下的类A
if hasattr(imp_module,‘A‘):
obj_A = getattr(imp_module,‘A‘)
obj_A.fun(‘‘)
# 获取test.py模块下的函数f
if hasattr(imp_module,‘f‘):
obj_f = getattr(imp_module,‘f‘)
obj_f()
# 打印内容如下
Hello World
对当前模块进行反射
class A:
num = 10
def fun(self):
print(‘Hello World‘)
# getattr正确的默认参数
obj = getattr(A,‘max‘,‘没找到‘)
print(obj)
# 打印内容如下
没找到
# getattr错误的默认参数
obj = getattr(A,‘max‘,default=‘没找到‘)
# 打印内容如下
TypeError: getattr() takes no keyword arguments
反射的应用
class DataAnalysis(FileOperation):
"""
数据分析处理类,主要负责解析client发送过来的指令。
"""
def syntax_analysis(self,recv_data, socket_obj, commom):
"""
负责解析客户端传来的数据。
:param recv_data:客户端执行的命令
:param socket_obj:socket对象
:param commom:数据对象
:return:
"""
# 用户要执行的命令可能是help 也可能是get 文件 客户端路径 还可能是cd 目录
# 所以首先要明确用户到底要执行什么用的命令,通过切割后获取第一个元素
# 我们通过第一个元素来判断用户到底要做什么,下面是判断用户到底用做什么
clientData = recv_data.split(" ")
if clientData[0] == ‘help‘:
pass
elif clientData[0] == ‘get‘:
pass
elif clientData[0] == ‘cd‘:
pass
elif clientData[0] == ‘put‘:
pass
...
class DataAnalysis(FileOperation):
"""
数据分析处理类,主要负责解析client发送过来的指令。
"""
def syntax_analysis(self,recv_data, socket_obj, commom):
"""
负责解析客户端传来的数据。
:param recv_data:客户端执行的命令
:param socket_obj:socket对象
:param commom:数据对象
:return:
"""
# 用户要执行的命令可能是help 也可能是get 文件 客户端路径 还可能是cd 目录
# 所以首先要明确用户到底要执行什么用的命令,通过切割后获取第一个元素
# 我们通过第一个元素来判断用户到底要做什么,下面是判断用户到底用做什么
clientData = recv_data.split(" ")
if hasattr(self, clientData[0]): # 判断用户执行的命令是否存在
get_fun = getattr(self, clientData[0]) # 获取命令的执行方法
get_fun(clientData, socket_obj, commom) # 执行对应的命令
else:
pass