Python开发-033_反射

1 反射的四个函数

反射,其实可以理解成python提供了四个函数,这四个函数可以使用字符串形式操作成员

class Person(object):
    def __init__(self,name,wx):
        self.name = name
        self.wx = wx
    def show(self):
        message = "姓名:{},微信:{}".format(self.name,self.wx)
        print(message)
user_object = Person('kinght','kinght666')

# 在对象中获取成员
## 对象.成员 获取数据
user_object.name
user_object.wx
user_object.show()
## 反射函数 getatter(对象名,'成员名')
getattr(user_object,'name')
getattr(user_object,'wx')
getattr(user_object,'show')() # getattr获取到方法名,需要加()运行
### 如果成员不存在,设置默认返回值
v1 = getattr(user_object,'admin','没有这个成员')
print(v1) # 没有这个成员

# 对象中设置成员
## 对象名.成员名 = 值 设置成员
user_object.age = 20
## 反射函数 setattr(对象名,'成员名称','值')
setattr(user_object,'sex','man')

# 对象中是否包含成员
## 反射函数 hasattr(对象,"成员名称") 返回值 True/False
v2 = hasattr(user_object,'sex')
print(v2) # True

# 删除对象中的成员
## del 对象名.方法名
del user_object.age
v3 = hasattr(user_object,'age')
print(v3)
## 反射函数 delattr(对象,"成员名称")
delattr(user_object,'sex')
v4 = hasattr(user_object,'sex')
print(v4) # False

以后如果再遇到 对象.成员 这种编写方式时,均可以基于反射来实现

# 案例 功能选择
class Account(object):
    def login(self):
        return '登陆界面'
    def register(self):
        return '注册页面'

def run():
    name = input("请输入功能选项login/register:")
    account_object = Account()
    try:
        method = getattr(account_object,name,None)()
        return method
    except TypeError as e:
        return "此功能模块不存在"
print(run())

2 一切皆对象

在Python中有这么句话:一切皆对象。 每个对象的内部都有自己维护的成员。由于反射支持以字符串的形式去对象中操作成员,所以基于反射也可以对类、模块中的成员进行操作

简单粗暴:只要看到 xx.oo 都可以用反射实现

2.1 对象是对象

class Person(object):
    
    def __init__(self,name,wx):
        self.name = name
        self.wx = wx
    def show(self):
        message = "姓名{},微信:{}".format(self.name,self.wx)
    
user_object = Person('kinght','kinght666')
getattr(user_object,'name')

2.2 类是对象

我们可以理解类是用一个名为class的类给实例化出来的东西

class Person(object):
    name = 'kinght'
v1 = getattr(Person,'name')
print(v1) # kinght

2.3 模块是对象

import re

v1 = re.match("\w+","dfjksdufjksd")
print(v1)

func = getattr(re,'match')
v2 = func("\w+","dfjksdufjksd")
print(v2)

3 import_module + 反射

注意!在大型项目中,这个非常有用!

3.1 import_module

在模块导入的时候其实是由两种方式的

'''案例1'''
# 传统方式
import random
v1 = random.randint(1,100)
print(v1)
# import_module 方式
from importlib import import_module
m = import_module('random')
v1 = m.randint(1,100)
print(v1)

'''案例2'''
# 传统方式
from requests import exceptions as m
# import_module 方式
from importlib import import_module
m = import_module("requests.exceptions")

'''案例3'''
# 传统方式
from requests.exceptions import InvalidURL as m
# import_module 方式
from importlib import import_module
m = import_module("requests.exceptions.InvalidURL") # 报错import_module只能导入到模块级别
# 修正办法
from importlib import import_module
m = import_module("requests.exceptions")
cls = m.InvalidURL # 通过模块获取类

3.2 简化代码案例

现在有一个需求,需要使用不同的路径向用户发送信息,并且,发送方式可能随时增减

|-app.py 入口文件
|-config.py 配置文件
|_handler 功能文件(发送信息的具体功能代码)
	|_email.py 发送邮件
	|_msg.py 发送短信

app.py

from importlib import import_module
import config

def run():
    for path in config.MESSAGE_HANDLER_LIST: # 读取配置文件信息
        m,c = path.rsplit(".",1) # 循环获取模块名、类名
        module = import_module(m) # 获得了模块名后,直接导入
        cls = getattr(module,c) # 使用反射直接获得类名
        obj = cls() # 实例化对象
        obj.send() # 运行方法

if __name__ == '__main__':
    run()

config.py

MESSAGE_HANDLER_LIST = [
    "handler.email.Email",
    "handler.msg.Msg",
]

功能模块-msg.py 简写

class Msg(object):
    def send(self):
        print("发送短信")

功能模块-email.py 简写

class Email(object):
    def send(self):
        print('发送邮件')

如果我们还需要增加模块,只需要在handler仲创建一个功能,然后写在配置文件中即可,减少模块,只需要将配置对应对应元素注释掉就行,不需要修改任何的app.py中代码


Python开发-033_反射
http://localhost:8080/archives/DKPVq5PZ
作者
kinght
发布于
2024年11月11日
更新于
2024年11月11日
许可协议