面向对象之反射

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(使用前将#替换为@)

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

  • Python获取正确时区的当前时间[重复]

    这个问题在这里已经有答案了 现在我用 import datetime print datetime datetime now strftime X 将当前时间显示为字符串 问题是 我的计算机正在运行Europe Berlin时区 这里不考虑
  • pip 安装最新的依赖版本

    当我使用安装包时pip install e 它仅安装不满足的依赖项并忽略依赖项升级 如何在每次运行时安装最新的依赖版本pip install e 我尝试过使用pip install upgrade e 但是使用这个选项没有任何改变 我仍然得
  • 从 asyncio 子进程获取实时输出

    我正在尝试使用 Python asyncio 子进程来启动交互式 SSH 会话并自动输入密码 实际用例并不重要 但它有助于说明我的问题 这是我的代码 proc await asyncio create subprocess exec ssh
  • 嵌套函数中的变量作用域

    有人可以解释为什么以下程序失败 def g f for in range 10 f def main x 10 def f print x x x 1 g f if name main main 带有消息 Traceback most re
  • 如何搜索一列并用找到的内容填充另一列?

    我有一个带有虚构人物数据的大熊猫数据框 下面是一个小例子 每个人都由一个数字定义 import pandas as pd import numpy as np df pd DataFrame Number 5569 3385 9832 64
  • 使用 Poetry 创建的 Python 项目:如何在 Visual Studio Code 中调试它?

    我有一个根据基本 Poetry 创建的 Python 项目指示 https python poetry org docs basic usage 项目文件夹是这样的 my project my project my project py F
  • 在Python中,如何通过去掉括号和大括号来打印Json

    我想以一种很好的方式打印 Json 我想去掉方括号 引号和大括号 只使用缩进和行尾来显示 json 的结构 例如 如果我有一个像这样的 Json A A1 1 A2 2 B B1 B11 B111 1 B112 2 B12 B121 1
  • Python:处理图像并保存到文件流

    我需要使用 python 处理图像 应用过滤器和其他转换 然后使用 HTTP 将其提供给用户 现在 我正在使用 BaseHTTPServer 和 PIL 问题是 PIL 无法直接写入文件流 因此我必须写入临时文件 然后读取该文件 以便将其发
  • 如何停止 PythonShell

    如何终止 停止 Node js 中 PythonShell 执行的 Python 脚本的执行 我在交互模式下运行 输出通过 socket io 发送到给定的房间 如果没有更多的客户端连接到这个房间 我想停止 python 脚本的执行 这是我
  • python 硒 按名称查找元素

    查找电子邮件输入的正确代码是什么https accounts google com ServiceLogin html 是
  • Pandas 根据条件替换数据框值

    我有一个主数据框 df Colour Item Price Blue Car 40 Red Car 30 Green Truck 50 Green Bike 30 然后我有一个价格修正数据框 df pc Colour Item Price
  • 在 Keras 中使用有状态 LSTM 训练多变量多级数回归问题

    我有时间序列P过程 每个过程的长度各不相同 但都有 5 个变量 维度 我试图预测测试过程的估计寿命 我正在用有状态的方法来解决这个问题LSTM在喀拉斯 但我不确定我的训练过程是否正确 我将每个序列分成长度的批次30 所以每个序列都是这样的形
  • 如何读取多个文件并将它们合并到一个 pandas 数据框中?

    我想读取位于同一目录中的多个文件 然后将它们合并到一个 pandas 数据框中 如果我这样做的话它会起作用 import pandas as pd df1 pd read csv data 12015 csv df2 pd read csv
  • 我应该在哪里对对象和字段进行 django 验证?

    我正在创建一个 Django 应用程序 它使用 Django Rest Framework 和普通的 django views 作为用户的入口点 我想对模型的独立字段以及整个对象进行验证 例如 字段 根据正则表达式函数输入的车牌是否正确 与
  • 从函数在 python 3 中创建全局变量

    我想知道为什么在函数结束后我无法访问变量 variable for raw data 代码是这样的 def htmlfrom Website URL import urllib request response urllib request
  • 如何在Python中不使用库函数将字符串转换为整数?

    我正在尝试转换 a 546 to a 546 不使用任何库函数 我能想到的 最纯粹 gt gt gt a 546 gt gt gt result 0 gt gt gt for digit in a result 10 for d in 01
  • 无法将 librosa 与 python 3 一起使用

    我已经在 Windows 上的 ubuntu 子系统上使用 pip3 正确安装了 librosa 但是当我尝试执行像这样的简单程序时 import librosa data sr librosa load sound mp3 print d
  • 混合语言源目录布局

    我们正在运行一个使用多种不同语言的大型项目 Java Python PHP SQL 和 Perl 到目前为止 人们一直在自己的私有存储库中工作 但现在我们希望将整个项目合并到一个存储库中 现在的问题是 目录结构应该是什么样的 我们应该为每种
  • Python 子进程:无法转义引号

    我知道以前曾问过类似的问题 但它们似乎都是通过重新设计参数的传递方式 即使用列表等 来解决的 但是 我这里有一个问题 因为我没有这个选项 有一个特定的命令行程序 我使用的是 Bash shell 我必须向其传递带引号的字符串 它不能不被引用
  • 如何从 Pandas 数据框函数调用中回顾之前的行?

    我正在研究 回测交易系统 我有一个包含 OHLC 数据的 Pandas 数据框 并添加了几个计算列 https stackoverflow com questions 12376863 adding calculated columns t

随机推荐

  • 堆排序的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
  • 面向对象之反射

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