反射机制是面向对象编程语言中比较重要的功能,可以动态获取对象信息以及动态调用对象,Python作为一门动态编程语言,当然也有反射机制,本文介绍Python反射函数使用方法。
目录反射Python反射函数反射函数使用方法dir()callable()isinstance()和type()hasattr()getattr()setattr()delattr()应用动态调用动态属性设置反射反射的概念是由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):删除模块中某个变量或者函数反射函数使用方法先创建一个类:
class Person(): def __init__(self, x, y): self.age = x self.height = y def __new__(cls, *args, **kwargs): print("begin!!!") return object.__new__(cls) def __call__(self, *args, **kwargs): print("hello!!!") def talk(self): print(f"My age is {self.age} and height is {self.height}")
dir()利用反射的能力,我们可以通过属性字典__dict__
来访问对象的属性:
p = Person(20, 180)print(p)p()print(p.__dict__)p.__dict__['age']=22print(p.__dict__)p.weight = 60print(p.__dict__)print(dir(p))
执行输出:
begin!!!<__main__.Person object at 0x000002484557BCC8>hello!!!{'age': 20, 'height': 180}{'age': 22, 'height': 180}{'age': 22, 'height': 180, 'weight': 60}['__call__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'height', 'talk', 'weight']
在实例创建之前调用__new__
方法,返回值(实例)将传递给__init__
方法的第一个参数。__new__
方法的详细介绍可参考:Python中的__new__
和__init__
实例化对象时会自动执行 __init__
方法打印一个对象时,会自动执行 __str__
方法调用实例化对象时,会自动触发 __call__
方法通过dir()
方法可以打印出了对象p的属性。接下来测试一下其他反射函数:
callable()if (callable(p)): print("p is callable")else: print("p is not callable")
Out:
p is callable
isinstance()和type()print(isinstance(p, Person))print(type(p) == Person)print(isinstance(p.age, int))print(type(p.age) == int)
Out:
TrueTrueTrueTrue
hasattr()print(hasattr(p,"talk"))print(hasattr(p.talk,"__call__"))
Out:
TrueTrue
getattr()print(getattr(p,"talk"))print(getattr(p.talk, "__call__"))if hasattr(p,'walk'): print(getattr(p,'walk'))else: print("I can't walk")print(getattr(p, "walk", None)) # 如果没有walk属性就返回None
Out:
<bound method Person.talk of <__main__.Person object at 0x000001FF52868288>><method-wrapper '__call__' of method object at 0x000001FF52155048>I can't walkNone
setattr()setattr(p,'walk','ON')if hasattr(p,'walk'): print(getattr(p,'walk'))else: print("I can't walk")print(p.__dict__)
Out:
ON{'age': 22, 'height': 180, 'weight': 60, 'walk': 'ON'}
delattr()delattr(p,'walk')if hasattr(p,'walk'): print(getattr(p,'walk'))else: print("I can't walk")print(p.__dict__)
Out:
I can't walk{'age': 22, 'height': 180, 'weight': 60}
@H_301_212@应用下面介绍两种Python反射的应用场景。
动态调用从前面举的例子中,我们了解到可以通过字符串来获取对象的属性(getattr()
),这是非常有用的一个功能。比如,一个类中有很多方法,它们提供不同的服务,通过输入的参数来判断执行某个方法,一般的使用如下写法:
class MyService(): def service1(self): print("service1") def service2(self): print("service2") def service3(self): print("service3")if __name__ == '__main__': Ser = MyService() s = input("请输入您想要的服务: ").strip() if s == "service1": Ser.service1() elif s == "service2": Ser.service2() elif s == "service3": Ser.service3() else: print("error!")
如果函数比较少这样写没有太大问题,如果有很多,这样写就比较复杂了,需要写大量else语句,可以使用反射机制来写:
if __name__ == '__main__': Ser = MyService() s = input("请输入您想要的服务: ").strip() if hasattr(Ser, s): func = getattr(Ser, s) func() else: print("error!")
这样是不是简洁了很多,上面的例子中,通过反射,将字符串变成了函数,实现了对对象方法的动态调用。
动态属性设置可以通过setattr()方法进行动态属性设置,在使用scapy库构造报文时,我们需要设置某些报文字段,然而网络协议的报文字段很多,在需要设置大量字段时,一个一个的赋值就很麻烦:
>>> ls(IP)version : BitFIEld (4 bits) = ('4')ihl : BitFIEld (4 bits) = ('None')tos : XByteFIEld = ('0')len : ShortFIEld = ('None')ID : ShortFIEld = ('1')flags : FlagsFIEld = ('<Flag 0 ()>')frag : BitFIEld (13 bits) = ('0')ttl : ByteFIEld = ('64')proto : ByteEnumFIEld = ('0')chksum : XShortFIEld = ('None')src : SourceIPFIEld = ('None')dst : DestIPFIEld = ('None')options : PacketListFIEld = ('[]')
可以使用setattr()方法来赋值:
from scapy.all import *fIElds = {"version":4, "src":"192.168.0.1","dst":"192.168.10.1"}ip = IP()for key, val in fIElds.items(): setattr(ip, key, val)
总结欢迎关注公众号:「测试开发小记」及时接收最新技术文章!
以上是内存溢出为你收集整理的Python反射介绍全部内容,希望文章能够帮你解决Python反射介绍所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)