Python

Python基础-21反射

2020-05-16  本文已影响0人  Surpassme

21 反射

21.1 反射概念

    反射主要是指程序可以访问、检测和修改其本身状态或行为的一种能力。在Python中最重要的4个方法如下所示:

    我们先来定义一个类,如下所示:

class Fruit:

    def __init__(self,name,color):
        self.name=name
        self.color=color

    def __str__(self):
        return f"Fruit is {self.name} color is {self.color}"

    def buy(self,price,totalWeight):
        return f"Fruit is {self.name},total price is {price*totalWeight}"

21.2 反射常用方法

21.2.1 getattr

    getattr主要用来获取指定字符串名称的对象属性,其使用方法如下所示:

getattr(object, name:string[, default]) -> value
  • name参数需要为string类型,不管是判断类属性还是类方法,其名称均以字符串形式传参
  • 如果属性存在,则返回其属性值,不存在则分为两种情况,一种是没有default参数时,则直接报错,如给定了default参数,对象没有其属性,则返回给定的default值
  • 如果获取的是类方法,则返回函数对象

    以前面定义的Fruit类为例

# 实例化一个类
apple=Fruit("apple","red")
# 利用反射获取类属性
print(getattr(apple,"name"))
print(getattr(apple,"color"))
# 利用反射获取类方法
print(getattr(apple,"buy"))
# 利用反射获取不存在的属性且有默认值
print(getattr(apple,"test","123"))
# 利用反射获取不存在的属性且没有默认值 - 报错
print(getattr(apple,"test"))

输出结果如下所示:

apple
red
<bound method Fruit.buy of <__main__.Fruit object at 0x000001E70B356288>>
123
Traceback (most recent call last):
  File "C:/Users/Surpass/Documents/PycharmProjects/SADCI/TempCode/reflectorSample.py", line 24, in <module>
    print(getattr(apple,"test"))
AttributeError: 'Fruit' object has no attribute 'test'

21.2.2 setattr

    setattr主要用于给对象添加一个类属性,如果添加的属性已经存在,则对其进行更新,否则则进行创建,其使用方法如下所示:

setattr(object, name:string, value)

name参数需要为string类型,不管是判断类属性还是类方法,其名称均以字符串形式传参

    示例如下所示:

# 实例化一个类
apple=Fruit("apple","red")
# 为实例添加一个类属性,并设置其值
setattr(apple,"destination","china")
print(f'第一次添加类属性,其值为(添加操作):{getattr(apple,"destination")}')
setattr(apple,"destination","USA")
print(f'第二次添加类属性,其值为(更新操作):{getattr(apple,"destination")}')

输出结果如下所示:

第一次添加类属性,其值为(添加操作):china
第二次添加类属性,其值为(更新操作):USA

21.2.3 hasattr

    hasattr常用于判断对象中是否存在其属性或方法,常用用法如下所示:

hasattr(object, name:string) -> bool

name参数需要为string类型,不管是判断类属性还是类方法,其名称均以字符串形式传参

    示例如下所示:

# 实例化一个类
apple=Fruit("apple","red")
# 判断属性或方法是否存在
print(f'对象是否存在其属性 name - {True if hasattr(apple,"name") else False }')
print(f'对象是否存在其属性 country - {True if hasattr(apple,"country") else False }')
print(f'对象是否存在其方法 buy - {True if hasattr(apple,"buy") else False }')

输出结果如下所示:

对象是否存在其属性 name - True
对象是否存在其属性 country - False
对象是否存在其方法 buy - True

21.2.4 delattr

    delattr常用于删除指定的属性,但不能用于方法,常用用法如下所示:

delattr(object, name:string)

name参数需要为string类型,不管是判断类属性还是类方法,其名称均以字符串形式传参

    示例如下所示:

# 实例化一个类
apple=Fruit("apple","red")
delattr(apple,"name")
# 判断属性或方法是否存在
print(f'对象是否存在其属性 name - {True if hasattr(apple,"name") else False }')
print(f'对象是否存在其属性 country - {True if hasattr(apple,"country") else False }')
print(f'对象是否存在其方法 buy - {True if hasattr(apple,"buy") else False }')

输出结果如下所示:

对象是否存在其属性 name - False
对象是否存在其属性 country - False
对象是否存在其方法 buy - True

在日常使用,一般会进行判断属性是否存在,然后再调用获取、添加和删除方法

21.3 示例

    以下用一个简单的示例来解释,反射在实际的应用案例。现在有一个场景,就是根据传入的不同的模块名称,调用不同的模块所对应方法,代码如下所示:

class ReflectSample:

    def moduleA(self):
        print("我是moduleA")

    def moduleB(self):
        print("我是moduleB")

    def moduleC(self):
        print("我是moduleC")

    def moduleD(self):
        print("我是moduleD")
while True:
    reflectSample=ReflectSample()
    choice=input("请输入模块名称")
    if choice == "moduleA":
       reflectSample.moduleA()
    elif choice == "moduleB":
        reflectSample.moduleB()
    elif choice == "moduleC":
        reflectSample.moduleC()
    elif choice == "moduleD":
        reflectSample.moduleD()
    else:
        print("输入的模块不存在")

测试结果如下所示:

请输入模块名称moduleA
我是moduleA
请输入模块名称moduleD
我是moduleD
请输入模块名称moduleF
输入的模块不存在
while True:
    reflectSample = ReflectSample()
    choice = input("请输入模块名称")
    if hasattr(reflectSample,choice):
        func=getattr(reflectSample,choice)
        func()
    else:
        print("输入的模块不存在")

测试结果如下所示:

请输入模块名称moduleA
我是moduleA
请输入模块名称moduleD
我是moduleD
请输入模块名称moduleF
输入的模块不存在

两种方法一对比,自然就觉得方法二更简洁,也更容易维护,更不用担心类中有很多个方法。

上一篇下一篇

猜你喜欢

热点阅读