13 编程的另一种重要思想
一. 正常函数版本的思路
1. notify.py
def wechat(content):
print('微信通知:%s'%content)
def qq(content):
print('qq通知:%s'%content)
def email(content):
print('邮箱通知:%s'%content)
2. start.py
from notify import *
def send_all(content):
wechat(content)
qq(content)
email(content)
if __name__ == '__main__':
send_all('jason要请我们吃饭, 大家办他!')
二. 模仿django的settings.py中多处利用指定字符串到类名的形式, 就可以通过字符串获取并执行相应的类中的方法和功能.
1. 目录结构
# 在一个包中有好几个模块
notify/ # 包
├── __init__.py
├── email.py
├── qq.py
└── wechat.py
├── settings.py
└── start.py
2. notify
2-1. __init__.py
关于import_module模块的使用连接: https://www.cnblogs.com/yang1333/articles/13070008.html
import settings
import importlib
def send_all(content):
for path_str in settings.NOTIFY_LIST: # 'notify.email.Email'
module_path, class_name = path_str.rsplit('.', maxsplit=1)
# module_path = 'notify.email' class_name = 'Email'
# 1 利用字符串导入模块
module = importlib.import_module(module_path) # from notify import email
# 2 利用反射获取类名
cls = getattr(module, class_name) # Email、QQ、Wechat
# 3 生成类的对象
obj = cls()
# 4 利用鸭子类型直接调用send方法
obj.send(content)
2-2. email.py
class Email(object):
def __init__(self):
pass # 发送邮箱需要做的前期准备工作
def send(self, content):
print('邮箱通知:%s' % content)
2-3. qq.py
class QQ(object):
def __init__(self):
pass # 发送qq需要做的前期准备工作
def send(self, content):
print('QQ通知:%s' % content)
2-4. wechat.py
class WeChat(object):
def __init__(self):
pass # 发送微信需要做的前期准备工作
def send(self, content):
print('微信通知: %s' % content)
3. settings.py
# 配置文件中以字符串的格式保存需要导入的内容
NOTIFY_LIST = [
'notify.email.Email',
'notify.qq.QQ',
'notify.wechat.WeChat',
# 'notify.msg.Msg',
]
4. start.py
# 用户需要发送消息通知只需要导入import notify即可操作使用实现一键发送消息
import notify
notify.send_all('jason要请我们吃饭, 大家办他!')
5. 中心思想总结
利用了面向对象以及面向对象的多态性(鸭子类型),
再通过定制配置文件并存放不同功能类的字符串路径,
接着使用导入包就是导入__init__.py文件的特性, 在包中定义一个方法,
方法中用importlib就轻松的导入了需要的模块.
再拿到这个模板通过获取的字符串路径最后一个类的字符串进行反射就实现了可以同时进行多个类中功能的集合.
合理的运用这种思想, 就可以只修改settings.py中的路径地址, 并合理的增添 或者 关闭某些功能. 重要的是关闭只需要注释即可.