Python基础学习之反射机制详解
作者:TtrOps 发布时间:2023-02-15 11:02:01
什么是反射
在Python中,反射是指通过一组内置的函数和语句,在运行时动态地访问、检查和修改对象的属性、方法和类信息的机制。Python中的反射机制非常强大,可以使程序更加灵活和可扩展。
Python中的反射主要涉及以下几个内置函数和语句:
getattr():获取对象的属性或方法。可以通过对象和字符串的方式传递属性或方法名,并且还可以提供一个默认值,用于在属性或方法不存在时返回。
setattr():设置对象的属性或方法。可以通过对象、字符串和值的方式传递属性或方法名和值。
delattr():删除对象的属性或方法。可以通过对象和字符串的方式传递属性或方法名。
dir():获取对象的所有属性和方法的列表。可以使用dir()函数来获取对象的所有属性和方法的列表。
type():获取对象的类型。可以使用type()函数来获取对象的类型信息。
inspect模块:该模块提供了更加高级的反射功能,可以用于获取函数和类的参数列表、注解、源代码等信息。
应用场景
反射在Python中的应用场景非常广泛,例如:
动态加载模块和类:使用反射可以在运行时动态加载模块和类,以便于程序更加灵活和可扩展。
动态修改对象属性和方法:使用反射可以在运行时动态修改对象的属性和方法,以便于程序更加灵活。
实现插件系统:使用反射可以实现插件系统,允许程序在运行时动态加载和卸载插件。
实现ORM框架:使用反射可以实现ORM框架,允许程序在运行时动态地将Python对象映射到数据库中的表格。
总之,反射是Python中一种非常有用的元编程技术,可以使程序更加灵活和可扩展。但是,在使用反射时需要谨慎,避免滥用,因为反射可能会影响性能并增加代码复杂度。
基本小栗子
1.访问对象属性
class MyClass:
def __init__(self, x):
self.x = x
obj = MyClass(42)
attr_name = "x"
attr_value = getattr(obj, attr_name)
print(f"{attr_name} = {attr_value}")
2.动态调用对象方法
class MyClass:
def my_method(self, x, y):
return x + y
my_object = MyClass()
result = getattr(my_object, "my_method")(1, 2)
print(result) # 输出 3
3.动态创建对象
class MyClass:
def __init__(self, x, y):
self.x = x
self.y = y
my_class = type("MyClass", (), {"x": 1, "y": 2})
my_object = my_class()
print(my_object.x, my_object.y) # 输出 1 2
4.动态导入模块
# 使用 importlib.import_module() 导入模块
import importlib
module_name = 'math'
module = importlib.import_module(module_name)
# 使用 getattr() 访问模块的属性
pi_value = getattr(module, 'pi')
print(pi_value) # 输出: 3.141592653589793
5.获取类属性
class MyClass:
my_class_attribute = "Hello World"
print(getattr(MyClass, "my_class_attribute")) # 输出 "Hello World"
6.检查对象是否具有属性
class MyClass:
def __init__(self):
self.my_attribute = "Hello World"
my_object = MyClass()
print(hasattr(my_object, "my_attribute")) # 输出 True
print(hasattr(my_object, "non_existent_attribute")) # 输出 False
7.动态获取类的方法列表
class MyClass:
def __init__(self):
self.my_attribute = 'Hello, World!'
def my_method(self):
print(self.my_attribute)
# 使用 dir() 获取类的方法列表
method_list = [method_name for method_name in dir(MyClass) if callable(getattr(MyClass, method_name))]
print(method_list) # 输出: ['__init__', '__module__', 'my_method']
8.动态调用模块中的函数
# 使用 importlib.import_module() 导入模块
import importlib
module_name = 'math'
module = importlib.import_module(module_name)
# 使用 getattr() 访问模块中的函数
sqrt_function = getattr(module, 'sqrt')
result = sqrt_function(4)
print(result) # 输出: 2.0
9.动态修改对象的属性
class MyClass:
def __init__(self):
self.my_attribute = 'Hello, World!'
my_object = MyClass()
# 使用 setattr() 修改对象的属性
setattr(my_object, 'my_attribute', 'Hello, Universe!')
print(my_object.my_attribute) # 输出: 'Hello, Universe!'
贴近实际应用的小场景
假设正在构建一个电商网站,并需要实现一个订单管理系统。这个系统需要支持多种订单类型(例如普通订单、抢购订单、团购订单等),每种订单类型有其独特的属性和方法。
为了实现这个系统,可以使用反射来动态地创建订单对象,并根据订单类型来调用相应的属性和方法。
首先,需要定义一个基本的订单类,该类包含所有订单类型的通用属性和方法。然后,可以创建一个名为 OrderFactory 的工厂类,该类负责根据订单类型创建订单对象。
下面是示例代码:
class Order:
def __init__(self, order_id, customer_name, product_id):
self.order_id = order_id
self.customer_name = customer_name
self.product_id = product_id
def calculate_total_price(self):
# 计算订单总价
pass
def validate_order(self):
# 验证订单是否合法
pass
def confirm_order(self):
# 确认订单
pass
class OrderFactory:
@staticmethod
def create_order(order_type, order_id, customer_name, product_id):
# 动态创建订单对象
order_class = globals().get(order_type)
if not order_class:
raise ValueError(f"Invalid order type: {order_type}")
return order_class(order_id, customer_name, product_id)
class FlashSaleOrder(Order):
def __init__(self, order_id, customer_name, product_id, discount):
super().__init__(order_id, customer_name, product_id)
self.discount = discount
def calculate_total_price(self):
# 计算限时抢购订单的总价(包含折扣)
pass
class GroupBuyOrder(Order):
def __init__(self, order_id, customer_name, product_id, group_size):
super().__init__(order_id, customer_name, product_id)
self.group_size = group_size
def calculate_total_price(self):
# 计算团购订单的总价(根据购买人数和商品单价)
pass
现在,可以使用 OrderFactory 来创建订单对象。例如,要创建一个限时抢购订单,可以使用以下代码:
order_type = "FlashSaleOrder"
order_id = "123"
customer_name = "Alice"
product_id = "456"
discount = 0.2
order = OrderFactory.create_order(order_type, order_id, customer_name, product_id, discount)
这将动态地创建一个 FlashSaleOrder 对象,并使用提供的参数初始化它。
另外,如果需要动态调用订单对象的方法,可以使用 Python 的内置反射机制。例如,要调用订单对象的 calculate_total_price 方法,可以使用以下代码:
method_name = "calculate_total_price"
method = getattr(order, method_name)
total_price = method()
这将动态地获取 order 对象的 calculate_total_price 方法,并调用它来计算订单的总价。
来源:https://mp.weixin.qq.com/s/NRSkzdAbcdF828YhFd88NA


猜你喜欢
- 在这里输入命令:操作命令:1.更新Anaconda:conda update conda更新所有包conda update --all3.添
- 前言Python中使用SSH需要用到OpenSSH,而OpenSSH依赖于paramiko模块,而paramiko模块又依赖于pycrypt
- 一、问题引发思考前阵子与同事探讨一个小需求时又遇到了按钮表示“动作”和表示“状态”间矛盾问题。想想这个问题多年前已经开始讨论了,所以在此整理
- 废话不多说了,直接上代码吧!import numpy as nparray = np.array([0, 0])for i in range
- 1.新式类与经典类在Python 2及以前的版本中,由任意内置类型派生出的类(只要一个内置类型位于类树的某个位置),都属于“新式类”,都会获
- 假设有如下目录结构:-- dir0| file1.py| file2.py| dir3| file3.py| dir4| file4.pyd
- #!/usr/bin/env python# -*- coding: utf-8 -*-'''''
- 看看下面:function zr4(y)' 准备数据dim z(10)z(1)="ONE&q
- GBK简体字符集的编码是同时用1个字节和2个字节来表示的。当高位是0x00~0x7f时,为一个字节,高位为0x80以上时用2个字节表示&qu
- 1、引言需要把.dat 格式 转化成 .txt格式2、实现##python批量更换后缀名import os# 列出当前目录下所有的文件fil
- 方法:通过desc:都无法实现:方法一:select sp.productid,sp.productname,ss.sku from sp_
- 为了更好的说明问题,首先引出下面的题目//请说明下面变量 a-d 的值 var a = [[1][1]]; var b = [['a
- java后台相关问题一,程序包lombok不存在通常报这个错误,是因为,我们的开发者工具idea没有安装lombok库导致的解决办法如下:提
- 这是我以前发表在经典论坛的帖子,现在转贴回来。仿淘宝网站的导航效果。此方法有几个优点:根据字数自适应项目长度不同的项目使用不同的颜色来区分无
- 本节主要介绍函数,但是函数是由操作组成的。那么就分为两部,一部分为操作一部分为函数。py世界中的操作。操作if:在学习任何一门语言中,关系i
- 在开发中有个需求是一个选择城市的列表,看了看做成 * 联动好像不是特别方便 还是做成一整页可以按导航选取的就可以了话不多说开始上码我用的是va
- 本文实例讲述了Python3读取文件常用方法。分享给大家供大家参考。具体如下:''''' Creat
- 表单外观的美化很多时候,我们仅仅为了实现数据采集这个功能来使用表单,常看到的表单都是“千人一面”、毫无
- 一、引言Windows Communication Foundation(WCF)是Microsoft为构建面向服务的应用程序而提供的统一编
- instanceof 运算符 和 is_a() 方法都是判断:某对象是否属于该类 或 该类是此对象的父类(用于确定一个 PHP 变量是否属于