ITPub博客

首页 > 数据库 > 数据库开发技术 > python面向对象编程篇(12):反射的简单实践

python面向对象编程篇(12):反射的简单实践

原创 数据库开发技术 作者:程序员小钟同学 时间:2021-03-16 18:00:38 0 删除 编辑

本文相关描述主要是个人的认知和见解,如有不当之处,还望各位大佬指正。

个人其他博客地址:

简书:https://www.jianshu.com/u/d6960089b087

掘金:https://juejin.cn/user/2963939079225608

小钟同学 | 文 【原创】| QQ:308711822

1 什么是反射

在python通过把字符串映射到实例的变量或者实例的方法,然后进行调用,这种就做反射。

和反射息息相关的一些自身函数:

  • getattr 获取指定字符串名称的对象属性
  • setattr 为对象设置一个对象
  • hasattr 判断对象是否有对应的对象(字符串)
  • delattr 删除指定属性

实例化对象的反射操作 如示例:

# -*- coding:utf-8 -*-


class Ape:
    # __slots__ = ['name']
    def __init__(self, name):
        self.name = name

a = Ape('我是你大爷')
# ==========
print(hasattr(a, "say"))  # false。因为存在talk方法
print(hasattr(a, "name"))  # True。因为存在name变量
# ==========
# 获取对象中的变量的指向的对象的值
n = getattr(a,"name")   # 获取name内存对象的的值
print(n)
n = getattr(a,"name2",'没有这个属性')   # 获取name内存对象的的值,,没有默认返回
print(n)
# ==========
# 为对象添加方法
def task(self):
    print("%s正在交谈"%self.name)
setattr(a,"task",task)   # 将task函数添加到对象中p中,并命名为task
a.task(a)
# 为对象添加属性
setattr(a,"age",56)   # 将task函数添加到对象中p中,并命名为task
print(a.age)
# ==========
# 删除对象中的变量

delattr(a,"age")

print(a.age) # AttributeError: 'Ape' object has no attribute 'age'

2 什么可以用于反射:

  • 实例化对象
  • 类
  • 其他模块
  • 本模块

场景场景:

  • 典型的使用场景就是web的URL路由。
  • 通过字符串导入模块。
  • 以字符串的形式使用模块的方法

3 类名的反射操作示例



class Ape:

    sex = "男"

    def __init__(self,name):
        pass


    @staticmethod
    def say(msg=""):
        print("开始说话:",msg)


# 获取类Ape 的动态方法并执行
getattr(Ape, "say")(msg="你大爷的")          # 666

4 反射应用动态模块的载入示例,

flask框架自动找到某个模块下相关的属性进行导入:


# 通过模块的属性值来导入---注意是模块 不是__init
def register_nestable_blueprint(app=None,project_name=None,api_name ='api',key_attribute = 'bp',hongtu='hongtu'):
    '''
    自动的导入的蓝图模块
    :param app:
    :return:
    '
''
    if not app:
        import warnings
        warnings.warn('路由注册失败,需要传入Flask对象实例')
        return None
    if project_name:
        # include_packages 这个设置为True很关键,它包含了 检测 对于的_init__内的属性,这个对于外层的遍历的来说很关键
        modules = find_modules(f'{project_name}.{api_name}', include_packages=True,recursive=True)
        lantu  =None
        for name in modules:
            # print('藍色的合適的話', name)
            module = import_string(name)
            if hasattr(module, key_attribute):
                # print('符合藍圖', name)
                # app.register_blueprint(module.mmpbp)
                lantu = getattr(module,key_attribute)
                app.register_blueprint(getattr(module,key_attribute))
            if hasattr(module, hongtu): pass
                # print('符合紅土', name)
                # getattr(module, hongtu).register(lantu)

    else:
        import warnings
        warnings.warn('路由注册失败,外部项目名称还没定义')


5 以字符串的形式使用模块的方法示例

#!/usr/bin/evn python
# coding=utf-8
from flask import Blueprint
bp = Blueprint('sys', __name__, url_prefix='/sys')


import os
import sys

pro_path = os.path.split(os.path.realpath(__file__))[0]
sys.path.append(pro_path)

def auto_register_edprint(edprint_key_attribute ='bp_edprint'):
    # 如果存在红图,则自动的导入红图的模块并且进行注册
    for root, dirs, files in os.walk(pro_path):
        # 遍历所有的文件夹
        if len(dirs)<=0:
            continue
        for d in dirs:
            if '__pycache__' not in root and '__pycache__' not in str(d):
                pass
                # intas = intas+1
                # 安装红图对象的执行的次数,等加载到最后的时候再执行操作
                install_redprint_index = 0
                curr_redprint_dir = os.path.join(root, d)
                # 安装当前文件夹是红图的对象名称
                for curr_redprint_dir_doot, curr_redprint_dir_dirs, curr_redprint_dir_files in os.walk(curr_redprint_dir):
                    for curr_redprint_dir_file in curr_redprint_dir_files:
                        # 查询当前存在红图对象属性的文件
                        name, ext = os.path.splitext(curr_redprint_dir_file)
                        # 判断非__init__ 是否存在对应的红图对象模块
                        if name != '__init__' and ext == '.py':
                            curr_redprint_module = __import__(d + '.' + name, fromlist=[''])
                            # module = import_string(name)
                            # if hasattr(module___sad, 'auto'):
                            #     auto = getattr(module___sad, 'auto')
                            # 动态的导入模块下某个方法
                            #     auto()
                            if hasattr(curr_redprint_module, edprint_key_attribute):
                                # 判断某个属性对象是否存在
                                cls = getattr(curr_redprint_module, edprint_key_attribute)
                                # 调用属性的方法
                                # cls.register2(bp)
                                install_redprint_index = install_redprint_index + 1
                                # 避免多次的加载红图对象
                                if install_redprint_index == len(curr_redprint_dir_files) - 1:
                                    # 当挂载完成所有的红图的路径之后,再执行对应的注册
                                    cls.register(bp)

                        else:
                            # 如果__init__ 本身自己就带有了红图的对象属性的话,
                            if name == '__init__' and ext == '.py':
                                curr_redprint_module = __import__(d + '.' + name, fromlist=[''])
                                if hasattr(curr_redprint_module, edprint_key_attribute):
                                    # 判断某个属性对象是否存在
                                    cls = getattr(curr_redprint_module, edprint_key_attribute)
                                    # 当直接的执行注册
                                    cls.register(bp)
                            pass



def auto_register_lanytu():
    # 如果存在红图,则自动的导入红图的模块并且进行注册
    for root, dirs, files in os.walk(pro_path):
        # 遍历所有的文件夹
        if len(dirs)<=0:
            continue
        for d in dirs:
            if '__pycache__' not in root and '__pycache__' not in str(d):
                pass
                # intas = intas+1
                # 安装红图对象的执行的次数,等加载到最后的时候再执行操作
                install_redprint_index = 0
                curr_redprint_dir = os.path.join(root, d)
                # 安装当前文件夹是红图的对象名称
                for curr_redprint_dir_doot, curr_redprint_dir_dirs, curr_redprint_dir_files in os.walk(curr_redprint_dir):
                    for curr_redprint_dir_file in curr_redprint_dir_files:
                        # 查询当前存在红图对象属性的文件
                        name, ext = os.path.splitext(curr_redprint_dir_file)
                        # 判断非__init__ 是否存在对应的红图对象模块
                        # 如果__init__ 本身自己就带有了红图的对象属性的话,
                        if name == '__init__' and ext == '.py':
                            curr_redprint_module = __import__(d + '.' + name, fromlist=[''])
                        pass

def auto_py():
    for root, dirs, files in os.walk(pro_path):
        # 导入非文件夹模块的文件
        for file in files:
            name, ext = os.path.splitext(file)
            if ext == '.py' and name != '__init__' and pro_path == root:
                __import__(name)
        # 如果存在红图,则自动的导入红图的模块并且进行注册
        if len(dirs)>0:
            pass

        break
    # 自动注册红图
    # auto_register_edprint()

# 自动导入蓝图
auto_py()
# 自动导入蓝图下的红图模块
# auto_register_edprint()
auto_register_lanytu()

End

纯属个人实践中相关经验阐述总结,如有纰漏,还希望大佬们多多提点!小钟同学 | 文  【原创】| QQ:308711822


原文作者:程序员小钟同学;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2021-02-20

  • 博文量
    224
  • 访问量
    111698