Python反射

1、何为反射

1.1、概念

反射(Reflection)是计算机科学中的一个术语,指的是一种在运行时动态地获取、操作和修改一个语言的特定对象的能力。在编程中,反射可以让程序在运行时动态地获取类的信息,包括类的属性、方法和构造函数等,而不需要在编译时确定。

使用反射,程序可以在运行时动态地创建一个对象、调用对象的方法、访问对象的属性并修改它们的值、获取对象所属的类的信息等。这种动态性使得程序能够根据运行时的条件来决定如何处理对象,从而增加了程序的灵活性和可扩展性。

在许多编程语言中都提供了反射的机制,例如Ja、 Go、C#和Python等。具体的实现方式和使用方法可能会有所差异,但核心的概念和作用是相似的。

1.2、用途

以下是一些编程反射的常见用途:

  1. 动态实例化对象:通过反射可以根据类名字符串实例化对象,而不需要提前知道类的具体类型。这对于需要根据配置文件或用户输入来动态创建对象非常有用。

  2. 动态调用方法:通过反射可以在运行时动态调用类的方法,包括私有方法。这对于需要根据运行时条件选择不同的方法执行逻辑非常有用。

  3. 动态访问字段:通过反射可以在运行时动态获取和修改类的字段值,包括私有字段。这对于需要在运行时获取和修改对象的属性非常有用。

  4. 获取类的信息:通过反射可以获取类的各种元数据信息,如类名、父类、实现的接口、构造方法、方法、字段等。这对于开发一些通用的工具和框架非常有用。

  5. 注解处理:通过反射可以获取类、方法、字段上的注解信息,并动态根据注解做一些处理,如生成文档、验证参数等。

  6. 动态代理:通过反射可以创建动态代理对象,用于在不修改现有类的情况下增强类的行为。

总体而来,静态类型的编程语言,例如java,反射API的能力要强于动态语言。

2、java反射案例

我们先来看看java版本的反射。假设我们有一个汽车类。该类的属性与方法都是私有的。正常是无法调用的。

public class Car {private static int output;private String brand;private int year;public Car() {}public Car(String brand, int year) {this.brand = brand;this.year = year;}private void drive() {System.out.println("Driving the car...");}public static int getOutput(){return output;}
}

使用反射,我们是可以实现动态创造类示例,调用私有方法,调用私有方法。 

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class ReflectExample {public static void main(String[] args) {try {// 获取Class对象Class<?> carClass = Class.forName("Car");// 实例化对象Constructor<?> constructor = carClass.getConstructor(String.class, int.class);Object carObject = constructor.newInstance("BMW", 2024);// 调用私有方法Method driveMethod = carClass.getMethod("drive");driveMethod.setAccessible(true);driveMethod.invoke(carObject);// 访问私有字段Field brandField = carClass.getDeclaredField("brand");brandField.setAccessible(true);String brand = (String) brandField.get(carObject);System.out.println("Car brand: " + brand);} catch (Exception e) {e.printStackTrace();}}
}

我们也可以查看所有的属性及方法(包括静态以及示例)

  public static void main(String[] args) {Class<Car> clazz = Car.class;List<String> instanceFields = new ArrayList<>();List<String> staticFields = new ArrayList<>();List<String> instanceMethods = new ArrayList<>();List<String> staticMethods = new ArrayList<>();for (Field field : clazz.getDeclaredFields()) {if (Modifier.isStatic(field.getModifiers())) {staticFields.add(field.getName());} else {instanceFields.add(field.getName());}}for (Method method : clazz.getDeclaredMethods()) {if (Modifier.isStatic(method.getModifiers())) {staticMethods.add(method.getName());} else {instanceMethods.add(method.getName());}}System.out.println("所有静态属性");System.out.println(staticFields);   //[output]System.out.println("所有实例属性");  System.out.println(instanceFields); //[brand, year]System.out.println("所有静态方法");System.out.println(staticMethods);   //[getOutput]System.out.println("所有实例方法");System.out.println(instanceMethods); //[drive]}

3、Python反射

3.1、反射API

Python中的反射API主要集中在hasattrgetattrsetattr这三个内置函数,以及delattr函数等。

需要注意的是,API涉及属性与方法时,不区分属性和方法(虽然英文单词表示属性,python类内部属性与方法在同一个dict),而不像java那样,属性与方法区别对应。

hasattr(object, name)判断对象是否具有某个属性或方法
getattr(object, name)获取对象的某个属性或方法
setattr(object, name,value)设置对象的某个属性或方法
delattr(object, name)删除对象的某个属性或方法
dir(obj)返回对象obj的所有属性和方法的名称列表
type(obj):返回对象obj的类型
inspect模块提供了更高级的反射功能,可以获取对象的签名、参数、源代码等信息。

3.2、反射案例

class MyClass:def __init__(self):self.x = 10self.y = 20def my_method(self):print("Hello, reflection!")def my_method2(self, word):print("Hello!", word)obj = MyClass()# 使用getattr获取属性值
print(getattr(obj, 'x'))  # 输出: 10# 使用setattr设置属性值
setattr(obj, 'x', 20)
print(obj.x)  # 输出: 20# 使用hasattr检查属性是否存在
print(hasattr(obj, 'x'))  # 输出: True
print(hasattr(obj, 'y'))  # 输出: False# 使用dir获取对象的所有属性和方法 (屏蔽内置属性)
attrs = [x for x in dir(obj) if not x.startswith('__')]
print(attrs)# 使用type获取对象的类型
print(type(obj))  # 输出: <class '__main__.MyClass'># 使用inspect模块获取对象的信息
import inspect# 获取方法签名
method_sig = inspect.signature(obj.my_method2)
print(method_sig)  # 输出: (word)# 获取方法的参数名称
method_params = method_sig.parameters
print([param for param in method_params])  # 输出: ['word']# 获取方法的源代码
method_source = inspect.getsource(obj.my_method)
print(method_source)  # 输出: def my_method(self):\n    print("Hello, reflection!")

如果dir()方法的参数是一个class的话,返回所有实例方法、静态方法,静态属性;如果dir()方法的参数是一个对象的话,返回所有实例方法、静态方法,静态属性,还有加上所有实例属性(构造函数内部申明的属性)。

class MyClass:staticField = 100def __init__(self):self.x = 10self.y = 20def my_method(self):print("Hello, reflection!")@staticmethoddef my_method2(self, word):print("Hello!", word)obj = MyClass()
static_attrs = [x for x in dir(MyClass) if not x.startswith('__')]
print(static_attrs)# 使用dir获取对象的所有属性和方法 (屏蔽内置属性)
attrs = [x for x in dir(obj) if not x.startswith('__')]
print(attrs)

3.3、与java的比较

3.3.1、访问实例属性的区别

java作为一门静态语言,在编译阶段已经确定了类的结构(包括静态方法,实例方法,静态属性,实例属性,即使热更新也无法改变类的结构)。因此,java可以直接通过获取所有字段,见上一节java反射案例。

python只有通过dir()方法传入对象参数的时候,才可以获取所有的字段(因为python允许运行期动态增减字段)。

3.3.2、通过构造函数反射生成实例

java允许反射获取class的指定构造函数,并动态创建实例。比较常见的做法是,每个类提供一个无参构造函数,根据反射依次获取所有字段的类型,动态设置。

public class Main {public static void main(String[] args) throws Exception{Class<?> carClass = Class.forName("Car");// 指定有参构造函数Constructor<?> constructor = carClass.getConstructor(String.class, int.class);Object car1 = constructor.newInstance("BMW", 2024);// 无参构造函数Object car2 = Class.forName("Car").newInstance();}
}

python实现同样的功能,道路显得有点曲折。无参构造函数内部申明所有的实例属性,反射创建无状态实例,通过dir()方法获取所有字段,再通过setattr()动态设值。

class MyClass:def __init__(self, name):self.name = namedef say_hello(self):print(f"Hello, {self.name}!")# 要创建一个类的实例,可以使用以下代码:
class_name = "MyClass"
args = ("John",)# 使用globals()函数来获取全局命名空间中的类,并使用type()函数来创建实例对象
if class_name in globals():class_object = globals()[class_name]instance = type(class_name)(*args)instance.say_hello()  # 输出: Hello, John!
else:print(f"Class {class_name} not found")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/6081.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《QT实用小工具·五十二》文本或窗口炫酷有趣的滚动条——果冻条

1、概述 源码放在文章末尾 该项目实现了文本或窗口纤细的滚动条——果冻条 一个可以像弓弦一样拉出来&#xff0c;并且来回弹动的普通滚动条。 思路为此&#xff0c;但发现实际效果更像条状果冻&#xff0c;并且略有谐音&#xff0c; 故&#xff0c;称之为——“果冻条”&am…

【QT学习】12.UDP协议,广播,组播

一。Udp详细解释 UDP&#xff08;User Datagram Protocol&#xff09;是一种无连接的传输层协议&#xff0c;它提供了一种简单的、不可靠的数据传输服务。与TCP相比&#xff0c;UDP不提供可靠性、流量控制、拥塞控制和错误恢复等功能&#xff0c;但由于其简单性和低开销&#x…

【Linux-点灯烧录-SD卡/USB烧写】

目录 1. 烧写方式2. 烧写之代码编译2.1 led.s->led.o2.2 led.o->led.elf2.3 led.elf->led.bin2.4 反汇编&#xff1a;led.elf->led.dis 3. 烧写之烧录到SD卡上&#xff1a;3.1 开启烧录软件权限&#xff1a;3.2 确定SD卡的格式&#xff1a;FAT323.3 烧录到SD卡上3.…

【蓝桥杯】基于STM32G431模块总结

目录 一.LED部分 二.按键部分 三.ADC部分 四.基于IIC的24c02读写部分&#xff08;EEPROM&#xff09; 五.LCD显示部分 六.定时器部分 1.定时器中断回调 2. PWM输出改变频率和占空比 3.输入捕获测量占空比和频率(利用主从模式) 4.方波输出回调 七.RTC部分 一.LED部分 …

【Vue3源码学习】— CH3.3 renderer.ts详解

renderer.ts详解 1.概念理解1.1 主要功能1.2 核心函数1.3 流程说明1.4 学习 render.ts2.createRenderer2.1 源码解析2.2 代码解释2.2.1 泛型参数2.2.2 函数参数2.3 使用示例2.4 总结1.概念理解 1.1 主要功能 功能描述渲染和更新 DOM渲染器的核心职责是将 VNode 树转换成 DOM 树…

学习Rust的第22天:mini_grep第2部分

书接上文&#xff0c;在本文中&#xff0c;我们学习了如何通过将 Rust 程序的逻辑移至单独的库箱中并采用测试驱动开发 (TDD) 实践来重构 Rust 程序。通过在实现功能之前编写测试&#xff0c;我们确保了代码的可靠性。我们涵盖了基本的 Rust 概念&#xff0c;例如错误处理、环境…

ChatGPT理论分析

ChatGPT "ChatGPT"是一个基于GPT&#xff08;Generative Pre-trained Transformer&#xff09;架构的对话系统。GPT 是一个由OpenAI 开发的自然语言处理&#xff08;NLP&#xff09;模型&#xff0c;它使用深度学习来生成文本。以下是对ChatGPT进行理论分析的几个主…

移动机器人系统与技术:自动驾驶、移动机器人、旋翼无人机

这本书全面介绍了机器人车辆的技术。它介绍了道路上自动驾驶汽车所需的概念。此外&#xff0c;读者可以在六足机器人的构造、编程和控制方面获得宝贵的知识。 这本书还介绍了几种不同类型旋翼无人机的控制器和空气动力学。它包括各种旋翼推进飞行器在不同空气动力学环境下的模…

基于vmware虚拟机中yum源的配置

1.首先需确保虚拟机中已经连接了光盘映像&#xff08;如图在虚拟机右下方从左往右第二个&#xff09; 2.在虚拟机中找到光盘映像文件&#xff08;默认在/dev的sr0&#xff09; 3.将光盘文件挂载&#xff08;挂载后才可读取&#xff09; 为方便每一次开机之后自动挂载&#xff…

学浪视频怎么下载保存到本地

你是否曾经因为想要保存一份珍贵的学浪视频却苦于无法下载而感到烦恼&#xff1f;现在&#xff0c;我将向你揭示一个简单易行的方法&#xff0c;让你轻松地将学浪视频保存到本地&#xff0c;随时随地享受学习的乐趣。你是否曾经因为想要保存一份珍贵的学浪视频却苦于无法下载而…

未来科技的前沿:深入探讨人工智能的进展、机器学习技术和未来趋势

文章目录 一、人工智能的定义和概述1. 人工智能的基本概念2. 人工智能的发展历史 二、技术深入&#xff1a;机器学习、深度学习和神经网络1. 机器学习2. 深度学习3. 神经网络 三、人工智能的主要目标和功能1. 自动化和效率提升2. 决策支持和风险管理3. 个性化服务和预测未来 本…

初始数据类型

注释补充 在我们编写任何代码的时候&#xff0c;都有一个叫做注释的功能 在golang中有两种 单行注释 // 如下图所示 加入了注释的话&#xff0c;代码在执行的时候会自动忽视这段内容 //fmt.Println("天上") //fmt.Println("天下") //fmt.Println("唯…

MySQL商城数据库88张表结构(46—50)

46、消息队列表 CREATE TABLE dingchengyu消息队列表 (id int(11) NOT NULL AUTO_INCREMENT COMMENT 序号,userId int(11) DEFAULT NULL COMMENT 用户id,msgTtype tinyint(4) DEFAULT 0 COMMENT 消息类型,createTime datetime DEFAULT NULL COMMENT 创建时间,sendTime datetim…

本地基于知识库的大模型的使用教程

本地基于知识库的大模型的使用教程 启动 双击 大模型启动.bat文件&#xff0c;内容如下&#xff1a; cmd /k "cd /d G:\Anaconda3\Scripts && activate.bat && cd /d D:\docdb_llm && conda activate python3.11 && python startup.py…

Vue表单项赋值后无法输入问题解决

问题背景 打开编辑页Form表单时&#xff0c;从后台接口获取已有数据并赋值到对应的输入框中&#xff0c;并通过v-model对数据进行绑定&#xff0c;会导致输入框输入无效的状态&#xff0c;且无报错信息 问题分析 Vue可以检测data中属性property的变化&#xff0c;但是不能直接…

vue2 + antvx6 实现流程图功能

导入关键包 npm install antv/x6 --save npm install antv/x6-vue-shape 保存插件 (可选) npm install --save antv/x6-plugin-clipboard antv/x6-plugin-history antv/x6-plugin-keyboard antv/x6-plugin-selection antv/x6-plugin-snapline antv/x6-plugin-stencil antv/…

windows上通过定时任务提交新增文件到SVN(bat双击可执行,但是通过定时任务后无法提交到svn)

这个要必须记录一下了&#xff0c;因为折腾了蛮久断断续续加起来花费的有一天多时间。因为这个跟上篇定时备份是一个事来的&#xff0c;备份完了不可能留在跟数据库相同的机器吧&#xff0c;这样的话也起不到备份的作用啊&#xff0c;所以就想着让它每天去定时备份&#xff0c;…

Web安全研究(七)

NDSS 2023 开源地址&#xff1a;https://github.com/bfpmeasurementgithub/browser-fingeprint-measurement 霍普金斯大学 文章结构 introbackground threat model measurement methodology step1: traffic analysisstep2: fingerprint analysis dataset attack statisticsbro…

【EI会议|稳定检索】2024年传感技术与图像处理国际会议(ICSTIP 2024)

2024 International Conference on Sensing Technology and Image Processing 一、大会信息 会议名称&#xff1a;2024年传感技术与图像处理国际会议会议简称&#xff1a;ICSTIP 2024收录检索&#xff1a;提交Ei Compendex,CPCI,CNKI,Google Scholar等会议官网&#xff1a;htt…

nginx变量自定义日志收集

内置变量 $remote_addr&#xff1b;存放了客户端的地址&#xff0c;注意是客户端的公网IP&#xff0c;也就是一家人访问一个网站&#xff0c;则会显示为路由器的公网IP。 $args&#xff1b;变量中存放了URL中的指令 [rootlocalhost conf.d]# cat pc.conf server {listen 80;se…