第三十四篇 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想要的方法

原文地址:https://www.cnblogs.com/victorm/p/9341003.html

时间: 2024-10-11 03:36:00

第三十四篇 Python面向对象之 反射(自省)的相关文章

三十九、python面向对象一

A.python面向对象 1.面向对象基础:面向对象三个特性:封装,继承,多态C# java 只能用面向对象编程Ruby,python 函数+面向对象 函数式编程:def 函数def f1(a): return "f1"def f2(b): return "f2" f1("www")f2("aaa") 面向对象式编程,类,def 方法class Func: def f1(self,a): return "f1&quo

python全栈开发【第十四篇】面向对象三大特性——继承

一.组合 组合:组合指的是,在一个类中以另外一个类的对象(也就是实例)作为数据属性,称为类的组合 也就是说:一个类的属性是另一个类的对象,就是组合 例子: 圆环是由两个圆组成的,圆环的面积就是外圆的面积减去内圆的面积.圆环的周长就是内圆的周长加上外圆的周长,这个时候,我们首先设计一个圆形类,计算一个圆的面积和圆的周长.然后在'圆环类'组合圆形的实例作为自己的属性来用(这样的目的就是为了不用在写面积和周长的方法了,直接组合圆类的面积和方法去求解.减少了代码的重用) #求圆环的面积和周长 from

第三十九篇 Python异常处理

一. 什么是异常 异常就是程序运行时发生的错误,在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序的运行也随之终止,在python中,错误触发的异常如下 错误分成两种: #语法错误示范一 if #语法错误示范二 def test: pass #语法错误示范三 class Foo pass #语法错误示范四 print(haha 1.语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正) #TypeError:int类型不可迭代 for i i

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

概述 异步通知是客户端开发中常见的需求,比如在一个网络处理线程中要通知UI线程更新等等. 通常在Windows编程中,为了方便,我们一般会向UI线程的窗口句柄Post/Send一个窗口消息从而达到将非UI线程的事件切换到UI线程处理的目的. 在SOUI引入通知中心以前要在SOUI中处理非UI线程事件我也推荐用上面的方法. 使用窗口消息至少有以下两个不足: 1.需要在线程中持有一个窗口句柄. 2.发出的消息只能在该窗口句柄的消息处理函数里处理. SNotifyCenter 最新的SOUI引入了一个

第三十四篇:Quartz2D绘图

1.Quartz2D在iOS开发中的价值 ?自定义view(自定义UI控件) 2.图形上下文 1)图形上下文(Graphics Context):是一个CGContextRef类型的数据 2)图形上下文的作用 ?保存绘图信息.绘图状态 ?决定绘制的输出目标(绘制到什么地方去?) (输出目标可以是PDF文件.Bitmap或者显示器的窗口上) 3)相同的一套绘图序列,指定不同的GraphicsContext,就可将相同的图像绘制到不同的目标上 4)Quartz2D提供了以下几种类型的Graphics

小刘同学的第一百三十四篇日记

坚持果然是最艰难的事. 今天还是更新不了博文,不过也不想勉强自己. 的确被论文所困,老师总是很严格的指出我的问题,并且让我逐一修改. 其实一直以来都很讨厌这样的自己. 什么事情都拖到最后-- 总是提前做完休息活动.娱乐活动-- 最应该,也是最需要做的东西,结果什么都没做-- 这样的自己,真是连自己都看不起呢. 马上就要变成社会人士了. 自己不在校园,更应该把任务和工作提前做好做完. 再考虑娱乐和休息. 说了这么多,也只是想提醒自己,也提醒大家. 一定是先完成工作.再休息娱乐ヽ(`Д′)? 牢记小

Python进阶(三十四)-Python3多线程解读

Python进阶(三十四)-Python3多线程解读 线程讲解 ??多线程类似于同时执行多个不同程序,多线程运行有如下优点: 使用线程可以把占据长时间的程序中的任务放到后台去处理. 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度. 程序的运行速度可能加快. 在一些等待的任务实现上如用户输入.文件读写和网络收发数据等,线程就比较有用了.在这种情况下我们可以释放一些珍贵的资源如内存占用等等. ??线程在执行过程中与进程还是有区别的.每个独立

JAVA之旅(三十四)——自定义服务端,URLConnection,正则表达式特点,匹配,切割,替换,获取,网页爬虫

JAVA之旅(三十四)--自定义服务端,URLConnection,正则表达式特点,匹配,切割,替换,获取,网页爬虫 我们接着来说网络编程,TCP 一.自定义服务端 我们直接写一个服务端,让本机去连接,可以看到什么样的效果 package com.lgl.socket; import java.io.IOException; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; publ

NHibernate 存储过程 第十四篇

NHibernate 存储过程 第十四篇 NHibernate也是能够操作存储过程的,不过第一次配置可能会碰到很多错误. 一.删除 首先,我们新建一个存储过程如下: CREATE PROC DeletePerson @Id int AS DELETE FROM Person WHERE PersonId = @Id; 修改映射文件,添加删除对象的存储过程: <?xml version="1.0" encoding="utf-8" ?> <hiber