什么是反射?

反射的概念是由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)) #
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}
#

Python一切皆对象,文件也是对象,所以文件也可反射

def say_hi():
print('你好啊')

test.py文件

# fanshe.py 文件
import test as obj # 导入test模块,重命名为obj print(obj) print(hasattr(obj,'say_hi')) # True
print(hasattr(obj,'say_hisssssssssssssssssssssssssssssssssssssssssss')) # False if hasattr(obj,'say_hi'):
func=getattr(obj,'say_hi')
func()
else:
print('其他的逻辑') x=111
y=222 # 执行结果
# 你好阿
# 需求:检测一下fanshe.py这个当前文件有没有某些属性

import test as obj  # 导入test模块,重命名为obj

print(obj)

print(hasattr(obj,'say_hi'))  # True
print(hasattr(obj,'say_hisssssssssssssssssssssssssssssssssssssssssss')) # False if hasattr(obj,'say_hi'):
func=getattr(obj,'say_hi')
func()
else:
print('其他的逻辑') x=111
y=222 # 关键问题是,上面拿到别人的导入就行了,那怎么拿到自己的呢? # import fanshe as obj1 # 在当前文件里是不可以再导入自己的
# 需要用sys模块来操作
import sys
obj1=sys.modules[__name__] print('===>',hasattr(obj1,'x'))

二. 为什么用反射?

好处一:实现可插拔机制

是项目中,一个项目有多个程序员写,如果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想要的方法

好处二:动态导入模块(基于反射当前模块成员)

模块的动态导入

所谓动态导入模块,就是模块名是字符串形式的,根据字符串使用importLib模块导入。

如果要导入的模块给你的是一个字符串,那怎么导入呢?目录结构如下:

需求是:要将m1下的t.py导入到01.动态导入模块.py文件里

# 1. 正常的导入及调用执行
from m1 import t
t.test1()
# 2. 现在有个新问题,要求你不能按照上面的方式到导入,给的是个字符串  'm1.t'
# 通过字符串方式导入模块
module_t = __import__('m1.t')
print(module_t)
# <module 'm1' (namespace)>
# 为什么导入的模块是m1,而不是t呢?而我们要导入的就是t模块啊?
'''
这种导入方式,不管你下面套多少层,返回的都是最顶层的模块
'''
# 调用:都需要通过最顶层的模块以.的方式,一层一层的往下找,直到调用你需要引用的模块
module_t.t.test1()
# 3. 利用importlib模块导入字符串形式的模块
import importlib
m = importlib.import_module("m1.t")
print(m)
# <module 'm1.t' from 'F:\\workspace\\Try2\\m1\\t.py'>
# 以这种方式导入,直接就定位到你想要调用的t模块了 # 调用
m.test1()

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

  1. 孤荷凌寒自学python第三十四天python的文件操作对file类的对象学习

     孤荷凌寒自学python第三十四天python的文件操作对file类的对象学习 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 一.close() 当一个file对象执行此方法时,将关闭当前 ...

  2. 三十九、python面向对象一

    A.python面向对象 1.面向对象基础:面向对象三个特性:封装,继承,多态C# java 只能用面向对象编程Ruby,python 函数+面向对象 函数式编程:def 函数def f1(a): r ...

  3. Python之路(第三十四篇) 网络编程:验证客户端合法性

    一.验证客户端合法性 如果你想在分布式系统中实现一个简单的客户端链接认证功能,又不像SSL那么复杂,那么利用hmac+加盐的方式来实现. 客户端验证的总的思路是将服务端随机产生的指定位数的字节发送到客 ...

  4. 第三十九篇 Python异常处理

    一. 什么是异常 异常就是程序运行时发生的错误,在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序的运行也随之终止,在python中,错误触发的异常如下 错误分成两种: #语法 ...

  5. C++第三十四篇 -- 安装Windows Driver后,编译以前项目出现打不开lib文件

    VS2017默认是没有安装WDK的,但是我们写驱动文件的话需要用到WDK.不过安装了WDK后,发现以前一些正常的项目在Release模式下编译会报LINK1104,无法打开.lib的错误 针对这个错误 ...

  6. Android UI开发第三十四篇——SlidingPaneLayout

    SlidingPaneLayout也是系统支持的高级控件,是Android团对在2013 google IO大会期间更新的Support库(Version 13)中新加入的重要的功能.它支持左右滑动菜 ...

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

    概述 异步通知是客户端开发中常见的需求,比如在一个网络处理线程中要通知UI线程更新等等. 通常在Windows编程中,为了方便,我们一般会向UI线程的窗口句柄Post/Send一个窗口消息从而达到将非 ...

  8. 第三十四篇-Palette(调色板)的使用

    由于屏幕录制图片转换关系,不甚清晰,还是附上效果图 可以看出,上面文字和背景颜色确实会根据图片的变化而变化. 里面有3个组件,toolbar,textview,imageview,其中textview ...

  9. 三十四、python中shutil模块的介绍

    '''A.shutil:高级的文件 文件夹 压缩包 处理模块''' import shutil '''1.copyfileobj(a1,a2,lenth):将文件内容拷贝到另一个文件中''' shut ...

随机推荐

  1. 学校管理系统设计java(数据库、源码、演讲内容、ppt等)

    该系统使用java语言编写 获取班级项目展第二名 项目展示:https://www.bilibili.com/video/av27910081/?p=10 登录截图 git:https://githu ...

  2. 【luogu P2324 [SCOI2005]骑士精神】 题解

    题目链接:https://www.luogu.org/problemnew/show/P2324 不懂怎么剪枝,所以说,,我需要氧气.. 第一道A* // luogu-judger-enable-o2 ...

  3. Zookeeper watch参照表

    Watcher 设置是开发中最常见的,需要搞清楚watcher的一些基本特征,对于exists.getdata.getchild对于节点的不同操 作会收到不同的 watcher信息.对父节点的变更以及 ...

  4. notepad++括号自动补全插件: XBracket Lite

    1.4.5.1. 通过XBracket Lite实现括号的自动补全 先去打开相应的设置: 再根据自己的需要去设置: 其中解释一下相应的选项的含义: Treat'' as brackets 把单引号', ...

  5. centos7下javac:未找到命令的问题

    在linux下编译java程序,执行javac编译生成class文件时,在centos7终端输入如,javac hello.java    会提示未找到指令,但用java -verison测试环境变量 ...

  6. IPv6静态路由、动态路由

    实验涉及命令以及知识补充 IPv6 接口必须配置 IPv6 地址和子网掩码 使用 ipv6 address ipv6-address/prefix-length [link-local | eui-6 ...

  7. CF605A Sorting Railway Cars(递推)

    题目描述 An infinitely long railway has a train consisting of n cars, numbered from 1 to n (the numbers ...

  8. 【赛事总结】◇赛时·8◇ AGC-027

    [赛时·8]AGC-027 日常AGC坑……还好能涨Rating +传送门+ ◇ 简单总结 感觉像打多校赛一样,应该多关注一下排名……考试的时候为了避免影响心态,管都没有管排名,就在那里死坑B题.最后 ...

  9. I/O流、字符集

    1)InputStream.OutPutStream是输出输入的基础流,均为抽象类,提供了read和writer方法,所有的子类均实现read和writer方法,read在遇到输入源的结尾时返回-1. ...

  10. 洛谷 P3952

    题目描述 小明正在学习一种新的编程语言 A++,刚学会循环语句的他激动地写了好多程序并 给出了他自己算出的时间复杂度,可他的编程老师实在不想一个一个检查小明的程序, 于是你的机会来啦!下面请你编写程序 ...