importlib模块&插拔式编程思想

importlib模块

python中,我们之前知道的的模块导入方式,如import ...或者from ... import ...这些属于静态导入。

importlib模块可以帮我们实现动态导入,类似反射的那种通过字符串的形式,动态导入模块。

import importlib

module1 = importlib.import_module('folder_name.file_name')					# 绝对导入
module2 = importlib.import_module('.file_name', package='folder_name')		# 相对导入


# 其中file_name就是py文件的名字
# 返回的就是file_name这个模块,然后就可以使用这个模块下面定义的变量属性、函数、类、方法等。

django中间件配置文件的插拔式编程思想

插拔式:在配置文件中注释或者添加新的字符串实现功能的取消或新增,是一种解耦合非常强的编程思想。

django中间件的配置文件就采用了插拔式的编程,底层利用的就是importlib模块这种动态导入模块的功能。

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    '你自己写的中间件1的路径',			# 增加一行,就执行这个功能
    '你自己写的中间件2的路径',			# 注释这一行,就不使用这个功能
 
]

模拟配置文件插拔式编程思想

需求:通过配置文件决定发送消息采用的渠道(qq\email\wechat)

文件目录结构

project
    ├── notify  				# 可以使用的发送消息的渠道包
    │   ├── __init__.py 		
    │   ├── qq.py   			# qq渠道
    │   └── wechat.py    		# wechat渠道
    │   └── email.py    		# email渠道
    ├── settings.py  	        # 配置文件
    └── run.py   				# 发布消息

配置文件settings.py

# NOTIFY_LIST列表内存放使用的发布渠道:'路径.xxx.文件名.类名'
NOTIFY_LIST = [
    'notify.email.Email',
    'notify.qq.Qq',
    'notify.wechat.Wechat',
]

执行文件run.py

import notify					# 导入包,即调用包内的__init__.py

notify.send_all('下课啦')		  # 调用send_all方法,发布消息

notify包内的__init__.py文件

import importlib
import settings


def send_all(content):
    for item in settings.NOTIFY_LIST:
        module_str, class_name = item.rsplit('.', maxsplit=1)
        # module_str = 'notify.qmail'
        # class_name = 'Email'
        
        module = importlib.import_module(module_str)		# 由字符串动态导入模块
        # module = email这个模块
        
        if hasattr(module, class_name):						# 反射判断,一种保证机制,有的话获取,否则抛异常
            obj = getattr(module, class_name)()				# obj就是 类Email加括号实例化的对象
            obj.send(content)								# 对象调用自己的方法,执行发布消息的任务
        else:
            raise NameError(f'cannot find {class_name}')

渠道包内每个渠道的写法,使用鸭子类型,统一调用方法。

# email.py
class Email():
    def send(self,content):
        print(f'email:{content}')
        
        
# qq.py
class QQ():
    def send(self,content):
        print(f'qq:{content}')
        
        
# wechat.py
class Wechat():
    def send(self,content):
        print(f'wechat:{content}')
posted @ 2020-07-26 11:22  the3times  阅读(449)  评论(0编辑  收藏  举报