第三十四篇 Python面向对象之 反射(自省)

Posted mamingchen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第三十四篇 Python面向对象之 反射(自省)相关的知识,希望对你有一定的参考价值。

什么是反射?

反射的概念是由Smith在1982年提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成就。

四个可以实现自省的函数,是Python的内置函数

    下列方法适用于类和对象
    • 先看这四个方法对实例(b1)的使用
# 演示代码
class BlackMedium:
    feature = Ugly
    def __init__(self, name, address):
        self.name = name
        self.address = address

    def sell_house(self):
        print("[%s] 是卖房子的,sb才从它这买" %self.name)

    def rent_house(self):
        print("[%s] 是租房子的,sb才从它这租,它黑人" %self.name)

# 实例化
b1 = BlackMedium(某某置业, 回龙观)
  • hasattr(object, name):判断object里有没有一个name字符串(‘属性名‘)对应的方法或属性。

  object:表示对象; name:属性名,是字符串形式;

# 检测数据属性
print(hasattr(b1, name))        # True     # b1.__dict__[‘name‘]
# 检测函数属性
print(hasattr(b1, sell_house))  # True
print(hasattr(b1, sell_housereqre))  # False
  • getattr(object, name, default=None): 获取属性值

  object:表示对象; name:属性名,是字符串形式;value:属性对应的值

# 获取属性的具体值
print(getattr(b1, name))   # 某某置业
print(getattr(b1, rent_house))  # <bound method BlackMedium.rent_house of <__main__.BlackMedium object at 0x00B52F50>>
func = getattr(b1, rent_house)
func()    # [某某置业] 是租房子的,sb才从它这租,它黑人
print(getattr(b1, feature))   # Ugly
# default 参数
print(getattr(b1, sell_house323, 没有这个属性)) # 没有这个属性

getattr()  # 等价于 b1.sell_house
  • setattr(object, name, value): 修改或者新增属性及值

  object:表示对象; name:属性名,是字符串形式;value:属性对应的值

# setattr设置数据属性
setattr(b1, sb, True)
setattr(b1, sb1, 1234)
setattr(b1, name, "万神置业")
setattr(b1, feature, 黑中介)
print(b1.__dict__)
#  {‘name‘: ‘万神置业‘, ‘address‘: ‘回龙观‘, ‘sb‘: True, ‘sb1‘: 1234, ‘feature‘: ‘黑中介‘}

# setattr设置函数属性
setattr(b1, funct, lambda x:x+1)
setattr(b1, funct1, lambda self:self.name+"ss")
print(b1.__dict__)
# {‘name‘: ‘万神置业‘, ‘address‘: ‘回龙观‘, ‘sb1‘: 1234, ‘feature‘: ‘黑中介‘, ‘funct‘: <function <lambda> at 0x02FEB618>}
# 调用新增的函数属性
print(b1.funct(10))     # 11
print(b1.funct1(b1))    # 万神置业ss
  • delattr(object, name)  删除属性。

  object:表示对象; name:属性名,是字符串形式

delattr(b1, sb)   # 等于 del b1.sb
print(b1.__dict__)
#  {‘name‘: ‘万神置业‘, ‘address‘: ‘回龙观‘, ‘sb1‘: 1234, ‘feature‘: ‘黑中介‘}
    •   再看这四个方法对类(BlackMedium)的使用 
# 定义类,但没有进行实例化
class BlackMedium:
    feture=Ugly
    def __init__(self,name,addr):
        self.name=name
        self.addr=addr

    def sell_hourse(self):
        print(【%s】 正在卖房子,傻逼才买呢 %self.name)

    def rent_hourse(self):
        print(【%s】 正在租房子,傻逼才租呢 % self.name)
# hasattr()
print(hasattr(BlackMedium,feture))  # True

print(getattr(BlackMedium,feture))

print(setattr(BlackMedium, feture, 黑中介))
print(getattr(BlackMedium, feture))  # 黑中介

delattr(BlackMedium, sell_hourse)
print(BlackMedium.__dict__)
# {‘__module__‘: ‘__main__‘, ‘feture‘: ‘黑中介‘, ‘__init__‘: <function BlackMedium.__init__ at 0x007D1B70>, ‘rent_hourse‘: <function BlackMedium.rent_hourse at 0x007D1AE0>, ‘__dict__‘: <attribute ‘__dict__‘ of ‘BlackMedium‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘BlackMedium‘ objects>, ‘__doc__‘: None}
#

二. 为什么用反射?

是项目中,一个项目有多个程序员写,如果A写程序的时候要用到B所写的类,但是B休假了,还没有完成他写的类,A想到了反射,使用了反射机制A可以继续完成自己的代码,等B休假回来后再继续完成类的定义并且实现A想要的功能。

总之,反射好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种“后期绑定”,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能。

演示:

技术分享图片
class FtpClient:
    ftp客户端,还没具体实现功能
    def __init__(self,addr):
        print("正在连接服务器[{}]".format(addr))
        self.addr = addr

f1 = FtpClient(192.168.123.123)
# f1.put()   # 因为B还没定义put()方法,所以会报错,不能这么干,所以需要用下面的判断做
if hasattr(f1,put):   # 判断f1里是否有put 方法
    func_get =  getattr(f1, put)   # 如果有,就可以get到这个方法
    func_get()   # 然后运行这个方法
else:
    print("执行其他逻辑")     # 如果没有put这个方法,就执行其他逻辑

#  结果
正在连接服务器[192.168.123.123]
执行其他逻辑
B只定义了接口,还没实现功能
技术分享图片
class FtpClient:
    ftp客户端,还没具体实现功能
    def __init__(self,addr):
        print("正在连接服务器[{}]".format(addr))
        self.addr = addr
    # B休假回来了,实现了put方法
    def put(self):
        print("文件开始上传了")

# from try import FtpClient
f1 = FtpClient(192.168.123.123)
# f1.put()
if hasattr(f1,put):   # 判断f1里是否有put 方法
    func_get =  getattr(f1, put)   # 如果有,就可以get到这个方法
    func_get()   # 然后运行这个方法
else:
    print("执行其他逻辑")     # 如果没有put这个方法,就执行其他逻辑

#结果
正在连接服务器[192.168.123.123]
文件开始上传了
B休假回来,实现了A想要的方法

 

以上是关于第三十四篇 Python面向对象之 反射(自省)的主要内容,如果未能解决你的问题,请参考以下文章

面向对象之: 反射和双下方法

面向对象之反射(定制)

第三十四篇 vue

python面向对象之反射

第三十四篇:在SOUI中使用异步通知

Python之面向对象-反射