面向对象之反射

2023-11-20

目录

反射

优点

实战案例

案例

使用内置函数改造

反射内建函数注意事项:实例方法绑定和非绑定的区别

动态增加属性方法的区别


反射

其实它的核心本质其实就是利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动!>>>>>通过字符串来操作对象的数据或方法.

python的四个重要内置函数:getattrhasattrdelattrsetattr较为全面的实现了基于字符串的反射机制。他们都是对内存内的模块进行操作,并不会对源文件进行修改。

    hasattr():判断对象是否含有某个字符串对应的属性
    getattr():获取对象字符串对应的属性
    setattr():根据字符串给对象设置属性
    delattr():根据字符串给对象删除属性
        

import sys
class Commons:
    @staticmethod
    def login():
        print("登录页面")
    @staticmethod
    def logout():
        print("退出页面")
    @staticmethod
    def home():
        print("这是网站主页")
this_moudle = sys.modules[__name__]
 
def run():
    inp = input("请输入想访问页面的URl:").strip()
    if hasattr(Commons,inp):
        func = getattr(Commons,inp,'没有这个页面')
        func()
    else:
        print("404!")
run()
class FtpServer:
    def serve_forever(self):
        while True:
            inp = input('input your cmd>>: ').strip()
            cmd, file = inp.split()
            if hasattr(self, cmd):  # 根据用户输入的cmd,判断对象self有无对应的方法属性
                func = getattr(self, cmd)  # 根据字符串cmd,获取对象self对应的方法属性
                func(file)
    def get(self, file):
        print('Downloading %s...' % file)

    def put(self, file):
        print('Uploading %s...' % file)
obj = FtpServer()
obj.serve_forever()

 

从上面的例子可以看到hasattr及getattr的用法,另外还有delattr和setattr方法类似

优点

        1、实现可插拔机制(对于代码来说),可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能

        2、动态导入模块(基于反射当前模块成员)

def run():
  inp = input("请输入您想访问页面的url: ").strip()
  modules, func = inp.split("/")
  obj = __import__(modules)
  if hasattr(obj, func):
    func = getattr(obj, func)
    func()
  else:
    print("404")
   
  run()

请输入您想访问页面的url: commons/home

执行结果为:这是网站主页

实战案例

1.加载配置文件纯大写的配置

# 配置文件加载:获取配置文件中所有大写的配置 小写的直接忽略  组织成字典
    import settings
    new_dict = {}
    # print(dir(settings))  # dir获取括号中对象可以调用的名字
    # ['AGE', 'INFO', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'desc', 'name']
    for i in dir(settings):
        if i.isupper():  # 如果名字是纯大写 那么获取该大写名字对应的值   'AGE'   'INFO'
            v = getattr(settings, i)
            new_dict[i] = v
    print(new_dict)

2.模拟操作系统cmd终端执行用户命令

class WinCmd(object):
        def dir(self):
            print('dir获取当前目录下所有的文件名称')

        def ls(self):
            print('ls获取当前路径下所有的文件名称')

        def ipconfig(self):
            print('ipconfig获取当前计算机的网卡信息')
    obj = WinCmd()
    while True:
        cmd = input('请输入您的命令>>>:')
        if hasattr(obj, cmd):
            cmd_name = getattr(obj, cmd)
            cmd_name()
        else:
            print('%s 不是内部或外部命令,也不是可运行的程序或批处理文件' % cmd)

接下来我们看看其他几个python内置的函数__getattr__、__setattr__、__delattr__

class Foo:
    def __init__(self,name):
        self.name = name
    def __setattr__(self, key, value):
#添加/修改属性会触发它的执行 
        if isinstance(value,str):
            self.__dict__[key] = value
            print("__setattr__")
        else:
            raise TypeError("必须为字符串")
    def __getattr__(self, item):
#只有在使用点调用属性且属性不存在的时候才会触发 
        print("getattr--->%s %s"%(item,type(item)))
    def __delattr__(self, item):
#删除属性的时候会触发 
        self.__dict__.pop(item)
        print("__delattr__")
 
f = Foo('yietong')
print(f.name)
f.age = '22'
print(f.age)
del f.age
print(f.__dict__)
print(f.xxxxx)

案例

需求:有一个 Point 类,查看它实例的属性,并修改它。动态为实例增加属性 

 

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return "Point:({},{})".format(self.x, self.y)

    def show(self):
        print(self, self.x, self.y)

p = Point(4, 5)
print(p)  # Point:(4,5)
print(p.__dict__)  # {'x': 4, 'y': 5}
p.__dict__['y'] = 16  
print(p.__dict__)  # {'x': 4, 'y': 16}
p.z = 10
print(p.__dict__)  # {'x': 4, 'y': 16, 'z': 10}
print(dir(p))
print(sorted(p.__dir__()))
Point:(4,5)
{'x': 4, 'y': 5}
{'x': 4, 'y': 16}
{'x': 4, 'y': 16, 'z': 10}
['__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__', 'show', 'x', 'y', 'z']
['__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__', 'show', 'x', 'y', 'z']

 

  • 上例通过属性字典 __dict__ 来访问对象的属性,本质上也是利用的反射的能力

  • 但是,上述的例子中,访问的方式不优雅, Python 提供了内置函数

 


使用内置函数改造

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return "Point:({},{})".format(self.x, self.y)

    def show(self):
        print(self, self.x, self.y)

p = Point(4, 5)
print(p)  # Point:(4,5)
print(p.__dict__)  # {'x': 4, 'y': 5}
# p.__dict__['y'] = 16
setattr(p, 'y', 16)
print(p.__dict__)  # {'x': 4, 'y': 16}
# p.z = 10
setattr(p, 'z', 10)
# print(p.__dict__)  # {'x': 4, 'y': 16, 'z': 10}
print(getattr(p, '__dict__'))  # {'x': 4, 'y': 16, 'z': 10}

# 动态调用方法
if hasattr(p, 'show'):
    print(getattr(p, 'show'))  # <bound method Point.show of <__main__.Point Object...>>
    getattr(p, 'show')()  # 调用此方法 Point:(4,16) 4 16

# 为类动态增加方法
if not hasattr(Point, 'add'):
    setattr(Point, 'add', lambda self, other: Point(self.x + other.x, self.y + other.y))

print(Point.__dict__['add'])  # 动态注入成功 <function <lambda> at ...>
print(Point.add)  # 动态注入成功 <function <lambda> at ...>

p1 = Point(2, 3)
p2 = Point(5, 6)
print(p1.add)  # 绑定方法 <bound method <lambda> of <__main__.Point object...>>
print(p1.add(p2))  # Point:(7,9)

# 为实例增加方法,未绑定,调用方法时,不能自动注入self
if not hasattr(p1, 'sub'):
    setattr(p1, 'sub', lambda self, other: Point(self.x - other.x, self.y - other.y))

print(p1.sub)  # <function <lambda> at ...>
print(p1.sub(p1, p2))  # 未绑定方法 Point:(-3,-3)

print(p1.__dict__)
print(Point.__dict__)
Point:(4,5)
{'x': 4, 'y': 5}
{'x': 4, 'y': 16}
{'x': 4, 'y': 16, 'z': 10}
<bound method Point.show of <__main__.Point object at 0x0000000002417490>>
Point:(4,16) 4 16
<function <lambda> at 0x00000000024CA160>
<function <lambda> at 0x00000000024CA160>
<bound method <lambda> of <__main__.Point object at 0x000000000244AF70>>
Point:(7,9)
<function <lambda> at 0x00000000024CA430>
Point:(-3,-3)
{'x': 2, 'y': 3, 'sub': <function <lambda> at 0x00000000024CA430>}
{'__module__': '__main__', '__init__': <function Point.__init__ at 0x00000000024CA280>, '__str__': <function Point.__str__ at 0x00000000024CA310>, 'show': <function Point.show at 0x00000000024CA3A0>, '__dict__': <attribute '__dict__' of 'Point' objects>, '__weakref__': <attribute '__weakref__' of 'Point' objects>, '__doc__': None, 'add': <function <lambda> at 0x00000000024CA160>}

反射内建函数注意事项:实例方法绑定和非绑定的区别

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def show(self):
        return 'Point: <{}, {}>'.format(self.x, self.y)
        
p1 = Point(2, 3)
print(1, p1.show())
print(2, getattr(p1, 'show'))
# 动态给类增加方法
print(3, setattr(Point, 'showy', lambda self: 'y is {}.'.format(self.y)))
print(4, Point.showy)
print(5, p1.showy())
# 动态给实例增加方法
print(6, setattr(p1, 'showx', lambda self: 'x is {}.'.format(self.x)))
# print(7, p1.showx())  # <lambda>() missing 1 required positional argument: 'self'
print(8, p1.showx(p1))
# print(9, Point.showx(p1))  # AttributeError: type object 'Point' has no attribute 'showx'
# 注意绑定和不绑定的区别,绑定的方法会自动注入self
# 实例动态添加的方法是没有绑定效果的,所以不会自动注入self
print(10, p1.showy)
print(11, p1.showx)
print(12, getattr(p1, 'showy'))
print(13, getattr(p1, 'showx'))
# 方法一般都式定义在类上,一般不需要定义在实例上
1 Point: <2, 3>
2 <bound method Point.show of <__main__.Point object at 0x00000282E3516700>>
3 None
4 <function <lambda> at 0x00000282E25E1CA0>
5 y is 3.
6 None
8 x is 2.
10 <bound method <lambda> of <__main__.Point object at 0x00000282E3516700>>
11 <function <lambda> at 0x00000282E23531F0>
12 <bound method <lambda> of <__main__.Point object at 0x00000282E3516700>>
13 <function <lambda> at 0x00000282E23531F0>

动态增加属性方法的区别

通过 setattr 动态增加方法和装饰器装饰一个类、Mixin方式的差异:setattr 是在运行时改变类或者实例的方式,但是装饰器或Mixin都是定义时就决定了,因此反射能力具有更大的灵活性。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

面向对象之反射 的相关文章

  • 没有名为 crypto.cipher 的模块

    我现在正在尝试加密一段时间 我最近得到了这个基于 python 的密码器 名为PythonCrypter https github com jbertman PythonCrypter 我对 Python 相当陌生 当我尝试通过终端打开 C
  • Django 代理模型的继承和多态性

    我正在开发一个我没有启动的 Django 项目 我面临着一个问题遗产 我有一个大模型 在示例中简化 称为MyModel这应该代表不同种类的物品 的所有实例对象MyModel应该具有相同的字段 但方法的行为根据项目类型的不同而有很大差异 到目
  • 在 python 程序中合并第三方库的最佳实践是什么?

    下午好 我正在为我的工作编写一个中小型Python程序 该任务需要我使用 Excel 库xlwt and xlrd 以及一个用于查询 Oracle 数据库的库 称为CX Oracle 我正在通过版本控制系统 即CVS 开发该项目 我想知道围
  • Django 管理员在模型编辑时间歇性返回 404

    我们使用 Django Admin 来维护导出到我们的一些站点的一些数据 有时 当单击标准更改列表视图来获取模型编辑表单而不是路由到正确的页面时 我们会得到 Django 404 页面 模板 它是偶尔发生的 我们可以通过重新加载三次来重现它
  • 将 Matplotlib 误差线放置在不位于条形中心的位置

    我正在 Matplotlib 中生成带有错误栏的堆积条形图 不幸的是 某些层相对较小且数据多样 因此多个层的错误条可能重叠 从而使它们难以或无法读取 Example 有没有办法设置每个误差条的位置 即沿 x 轴移动它 以便重叠的线显示在彼此
  • OpenCV Python cv2.mixChannels()

    我试图将其从 C 转换为 Python 但它给出了不同的色调结果 In C Transform it to HSV cvtColor src hsv CV BGR2HSV Use only the Hue value hue create
  • Python(Selenium):如何通过登录重定向/组织登录登录网站

    我不是专业程序员 所以请原谅任何愚蠢的错误 我正在做一些研究 我正在尝试使用 Selenium 登录数据库来搜索大约 1000 个术语 我有两个问题 1 重定向到组织登录页面后如何使用 Selenium 登录 2 如何检索数据库 在我解决
  • 使用带有关键字参数的 map() 函数

    这是我尝试使用的循环map功能于 volume ids 1 2 3 4 5 ip 172 12 13 122 for volume id in volume ids my function volume id ip ip 我有办法做到这一点
  • Django:按钮链接

    我是一名 Django 新手用户 尝试创建一个按钮 单击该按钮会链接到我网站中的另一个页面 我尝试了一些不同的例子 但似乎没有一个对我有用 举个例子 为什么这不起作用
  • Python - StatsModels、OLS 置信区间

    在 Statsmodels 中 我可以使用以下方法拟合我的模型 import statsmodels api as sm X np array 22000 13400 47600 7400 12000 32000 28000 31000 6
  • 根据列值突出显示数据框中的行?

    假设我有这样的数据框 col1 col2 col3 col4 0 A A 1 pass 2 1 A A 2 pass 4 2 A A 1 fail 4 3 A A 1 fail 5 4 A A 1 pass 3 5 A A 2 fail 2
  • 是否可以忽略一行的pyright检查?

    我需要忽略一行的pyright 检查 有什么特别的评论吗 def create slog group SLogGroup data Optional dict None SLog insert one SLog group group da
  • 测试 python Counter 是否包含在另一个 Counter 中

    如何测试是否是pythonCounter https docs python org 2 library collections html collections Counter is 包含在另一个中使用以下定义 柜台a包含在计数器中b当且
  • 以编程方式停止Python脚本的执行? [复制]

    这个问题在这里已经有答案了 是否可以使用命令在任意行停止执行 python 脚本 Like some code quit quit at this point some more code that s not executed sys e
  • 使用 Tkinter 显示 numpy 数组中的图像

    我对 Python 缺乏经验 第一次使用 Tkinter 制作一个 UI 显示我的数字分类程序与 mnist 数据集的结果 当图像来自 numpy 数组而不是我的 PC 上的文件路径时 我有一个关于在 Tkinter 中显示图像的问题 我为
  • Python 函数可以从作用域之外赋予新属性吗?

    我不知道你可以这样做 def tom print tom s locals locals def dick z print z name z name z guest Harry print z guest z guest print di
  • 如何使用Python创建历史时间线

    So I ve seen a few answers on here that helped a bit but my dataset is larger than the ones that have been answered prev
  • 使用 \r 并打印一些文本后如何清除控制台中的一行?

    对于我当前的项目 有一些代码很慢并且我无法使其更快 为了获得一些关于已完成 必须完成多少的反馈 我创建了一个进度片段 您可以在下面看到 当你看到最后一行时 sys stdout write r100 80 n I use 80覆盖最终剩余的
  • 从列表指向字典变量

    假设你有一个清单 a 3 4 1 我想用这些信息来指向字典 b 3 4 1 现在 我需要的是一个常规 看到该值后 在 b 的位置内读写一个值 我不喜欢复制变量 我想直接改变变量b的内容 假设b是一个嵌套字典 你可以这样做 reduce di
  • Statsmodels.formula.api OLS不显示截距的统计值

    我正在运行以下源代码 import statsmodels formula api as sm Add one column of ones for the intercept term X np append arr np ones 50

随机推荐

  • 堆排序的topk问题+归并排序+六大排序总结

    回忆一下堆排序 思路 sift函数 调整 将父亲和孩子 左孩子和右孩子中最大的那个数 然后和父亲比较 如果孩子大就将孩子的位子变为下一个父亲 往下拉 并且将孩子的值赋给他的父亲 j lt high 条件认可 防止父亲在最后一层 魔法般的对应
  • Tensorflow的Win10、CPU版本安装

    1 Anaconda的安装 Miniconda的安装 Anaconda的安装链接 https www anaconda com products distribution 如图所示 点击箭头所指 可以安装anaconda的最新版本 Mini
  • elementui 禁止浏览器自动填充用户名密码

    浏览器这功能在登录的时候挺好用的 但是在注册和管理的时候就很难受了 所以 在普通的input上直接off就行了
  • 华为虚拟机服务器怎么使用教程,虚拟机装服务器教程

    虚拟机装服务器教程 内容精选 换一换 应用容器化改造有三种方式 您可单击这里查看 本教程以某游戏为例 将该游戏进行微服务的架构改造 再进行容器化 本教程不对改造细节做深度讲解 仅讲解大致的建议 如需要详细了解容器化改造的过程 请单击服务咨询
  • 攻防世界adworld-hit-the-core

    hit the core 题目来源 CTF 题目描述 暂无 题目附件 下载附件 kwkl kwkl strings home kwkl 桌面 8deb5f0c2cd84143807b6175f58d6f3f core CORE code c
  • 【视频流上传播放功能】前后端分离用springboot-vue简单实现视频流上传和播放功能【详细注释版本,包含前后端代码】

    前言 我是前端程序猿一枚 不是后端的 如有写的有不规范的地方别介意哈 自己摸索了两天算是把这个功能做出来了 网上看了很多帖子没注释说实话 我看的基本是懵逼的 毕竟没有系统学过 所以现在做出来了就总结一下 自己多写点注释解释一下逻辑 让前端的
  • SpringBoot+MyBatisPlus+Thymeleaf+AdminLTE增删改查实战

    说明 AdminLTE是网络上比较流行的一款Bootstrap模板 包含丰富的样式 组件和插件 非常适用于后端开发人员做后台管理系统 因为最近又做了个后台管理系统 这次就选的是AdminLTE做主题模板发现效果不错 这里我把最核心的Spri
  • 华为机考练习python

    HJ108 求最小公倍数 while True try a b map int input split for i in range 1 b 1 if a i b 0 print a i break except break HJ107 求
  • linux中256错误,YUM安装遭遇: [Errno 256] No more mirrors to try

    把YUM配置好后 使用yum命令进行安装时 出现了如下错误 Downloading Packages ftp 192 168 220 46 RHEL6 2 x64 Server libaio devel 0 3 107 10 el6 x86
  • Calling a v8 javascript function from c++ with an argument

    Calling a v8 javascript function from c with an argument up vote 18 down vote favorite 8 I am working with c and v8 and
  • 笔试面试常考数据结构-单链表常用操作编程实现

    单链表是笔试以及面试手写代码中常考的数据结构之一 下面实现了单链表的常见操作 创建单链表 删除节点 打印单链表 包括正向打印以及逆向打印 反转单链表 找出单链表的倒数第K个节点 合并两个有序单链表等操作 代码 C cpp view plai
  • 【数据治理模型】哪种模型最适合您的组织?

    内部数据治理 第 2 部分 数据治理模型 在本系列的第一部分中 我们定义了数据治理并研究了导致大规模清理项目的失误 在这篇文章中 我们将研究常见的数据治理模型 哪些模型最适合不同类型的组织 没有单一的数据治理模型适合所有组织 在当今的业务中
  • RedisTemplate连接不释放导致服务异常

    最近在给一个项目做压测 刚开始时很正常 过一会服务就无法正常访问了 停止了压测任务再调用接口也同样没有响应 经排查是redis连接池没有释放导致的 解决方法 方法一 全局关闭事务 找到redis配置 将 enableTransactionS
  • jxl分割excel文件

    最近在实施一个项目 其中一项工作是处理历史数据 客户提供过来的数据是excel表格 超过20万条记录 由于目标系统导入限制 每次只能导入大小不超过8M的文件 所以需要对这些数据进行分割处理 在手工处理一遍后 觉得可以通过写一个程序来自动实现
  • 服务器 声音文件 nginx,docker nginx搭建视频音频服务器

    1 docker pull nginx 2 创建 nginx conf user nobody worker processes 1 error log logs error log error log logs error log not
  • python统计三国高频词,画条形图,绘词云图

    文章目录 前言 思路 代码 效果 总结 前言 记录一次期末作业 要求 1 统计三国演义 下卷 前十的高频词 含出现次数 2 根据上题结果 绘制高频词出现次数的条形图 3 生成三国演义 下卷 词云图 思路 1 open打开读取整篇文档 2 使
  • Vetur can‘t find `package.json`

    Vetur can t find package json 重新装了一下vscode 重新装vetur插件的时候右下角老是弹出提示 并且vetur的格式化也用不了了 我的解决办法是重新安装了vetur的版本 扩展里面找到vetur插件 点击
  • powershell报错:“irm : 请求被中止: 未能创建 SSL/TLS 安全通道“

    问题描述 powershell 执行下载的时候 报错 irm 请求被中止 未能创建 SSL TLS 安全通道 此时系统 所有的网络下载 经过https安全加密方式的TLS请求都会报错 因为加密版本不匹配的问题 可以通过以下命令 查看当前加密
  • TypeScript Property ‘XXX‘ does not exist on type ‘never‘.

    开发过程中出现这个错误是因为Typescript在执行代码检查时在该对象没有定义相应属性 这个错误不致命 遇到该错误有以下几种解决办法 1 将对象设置成 any this targetArray this options find item
  • 面向对象之反射

    目录 反射 优点 实战案例 案例 使用内置函数改造 反射内建函数注意事项 实例方法绑定和非绑定的区别 动态增加属性方法的区别 反射 其实它的核心本质其实就是利用字符串的形式去对象 模块 中操作 查找 获取 删除 添加 成员 一种基于字符串的