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}')