反射机制是面向对象编程语言中比较重要的功能,可以动态获取对象信息以及动态调用对象,Python作为一门动态编程语言,当然也有反射机制,本文介绍Python反射函数使用方法。
反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。
在程序运行时可以获取对象类型定义信息,例如,Python中的type(obj)将返回obj对象的类型,这种获取对象的type、attribute或者method的能力称为反射。通过反射机制,可以用来检查对象里的某个方法,或某个变量是否存在。也就是可以通过字符串映射对象的方法或者属性。
Python反射函数
Python反射常用的内置函数
- type(obj):返回对象类型
- isinstance(object, classinfo):判断一个对象是否是一个已知的类型,类似 type()
- callable(obj):对象是否可以被调用
- dir([obj]):返回obj属性列表
- getattr(obj, attr):返回对象属性值
- hasattr(obj, attr):判断某个函数或者变量是否存在
- setattr(obj, attr, val):给模块添加属性(函数或者变量)
- delattr(obj, attr):删除模块中某个变量或者函数
反射函数使用方法
先创建一个类:
1 | class Person(): |
dir()
利用反射的能力,我们可以通过属性字典__dict__
来访问对象的属性:
1 | p = Person(20, 180) |
执行输出:
1 | begin!!! |
- 在实例创建之前调用
__new__
方法,返回值(实例)将传递给__init__
方法的第一个参数。__new__
方法的详细介绍可参考:Python中的__new__
和__init__
- 实例化对象时会自动执行
__init__
方法 - 打印一个对象时,会自动执行
__str__
方法 - 调用实例化对象时,会自动触发
__call__
方法 - 通过
dir()
方法可以打印出了对象p的属性。
接下来测试一下其他反射函数:
callable()
1 | if (callable(p)): |
Out:
1 | p is callable |
isinstance()和type()
1 | print(isinstance(p, Person)) |
Out:
1 | True |
hasattr()
1 | print(hasattr(p,"talk")) |
Out:
1 | True |
getattr()
1 | print(getattr(p,"talk")) |
Out:
1 | <bound method Person.talk of <__main__.Person object at 0x000001FF52868288>> |
setattr()
1 | setattr(p,'walk','ON') |
Out:
1 | ON |
delattr()
1 | delattr(p,'walk') |
Out:
1 | I can't walk |
应用
下面介绍两种Python反射的应用场景。
动态调用
从前面举的例子中,我们了解到可以通过字符串来获取对象的属性(getattr()
),这是非常有用的一个功能。比如,一个类中有很多方法,它们提供不同的服务,通过输入的参数来判断执行某个方法,一般的使用如下写法:
1 | class MyService(): |
如果函数比较少这样写没有太大问题,如果有很多,这样写就比较复杂了,需要写大量else语句,可以使用反射机制来写:
1 | if __name__ == '__main__': |
这样是不是简洁了很多,上面的例子中,通过反射,将字符串变成了函数,实现了对对象方法的动态调用。
动态属性设置
可以通过setattr()方法进行动态属性设置,在使用scapy库构造报文时,我们需要设置某些报文字段,然而网络协议的报文字段很多,在需要设置大量字段时,一个一个的赋值就很麻烦:
1 | ls(IP) |
可以使用setattr()方法来赋值:
1 | from scapy.all import * |
本文标题:Python反射介绍
文章作者:hiyo
文章链接:https://hiyongz.github.io/posts/python-notes-for-reflection/
许可协议:本博客文章除特别声明外,均采用CC BY-NC-ND 4.0 许可协议。转载请保留原文链接及作者。