详解Python为什么不用设计模式


Posted in Python onJune 24, 2021

前言

刚刚看了EuroPython 2017一篇演讲,Why You Don't Need Design Patterns in Python,为什么python不用设计模式。演讲者是STXNEXT的Sebastian Buczynski。

他对设计模式的定义是:

  • 常见问题的通用可复用解决方案
  • 定型的最佳实践

他说设计模式是一种似曾相识(Anology),是一种大纲(Outline),他认为设计模式并不是拿来就能用的。

Singleton

详解Python为什么不用设计模式

第一个是Singleton模式,Singleton的精髓就是任何时候,只有一个类的实例。

《设计模式》里面给出的Singleton代码是

声明:

class Singleton {
public:
	static Singleton* Instance();
protected:
	Singleton();
private:
	static Singleton* _instance;
};

实现:

Singleton* Singleton::_instance = 0;

Sebastian 在 Google 上面找Singleton的Python实现,找到了以下代码:

声明:

class Singleton:
	_instance = None
	def __new__(cls, *args, **kwargs):
		if not cls._instance:
			cls._instance = super().__new__(cls, *args, **kwargs)
		return cls._instance

实现:

one_instance = Singleton()
another_instance = Singleton()
one_instance is another_instance # True

Sebastian指出,照抄C++,当然也可以解决问题,但是在python里面有更好的解决方案。比如,可以用@classmethod。不过,最好的解决方案是直接用module。因为module本身就是唯一的,相当于module就实现了singleton,那么,我们为什么要大费周章,搞一个singleton出来呢?

我回忆了一下,尽管Singleton是最简单的设计模式了,但是,我这么多年一直没用。以前写C#的时候,我用的是静态类,静态类本身就是唯一的,所以我不需要singleton。当然,我看到有人也用C#写了和C++一样的Singleton,但是我觉得解决问题就可以了,没必要为了写设计模式而写设计模式。同样,写VB.net的时候,我直接用的module,也不需要singleton。

结论:当年《设计模式》里面的Singleton模式,是为了只有一个类实例。如果编程语言本身,如python, c#, vb.net,已经提供了这样的能力,就没有必要再用C++的套路了。或者说,设计模式就不需要了。

Facade

详解Python为什么不用设计模式
详解Python为什么不用设计模式

(以上图片来自参考[1])

Facade的基本概念是,子系统用Facade来屏蔽内部的复杂实现。

这时,我们可以把子系统的python文件统一放在一个文件夹里,然后在这个文件夹里放一个__init__.py文件。

详解Python为什么不用设计模式

Command

Command模式把请求封装成对象。

Sebastian认为,在python里面,函数就是一等公民,所以没有必要创建对象。

def command(discount_rate):
some_obj.notify_users_about_discount()

也可以用functools创建command

import functools
command = functools.partial(
some_obj.notify_users_about_discount, discount_rate=0.5
)
command()
# equals to
some_obj.notify_users_about_discount(discount_rate=0.5)

Visitor

Python里面没有接口,没有方法重载。那么怎么实现Visitor呢?

Sebastian指出,可以用@SingleDispatch。

from functools import singledispatch
@singledispatch
def visit(node):
	type_name = type(node).__name__
	raise AttributeError(f'No handler found for {type_name}')
from ast_nodes import Assign, FunctionDef
@visit.register(Assign)
def visit(node):
	pass
@visit.register(FunctionDef)
def visit(node):
	pass

我们看到,这里的实现,并没有class。

Decorator

Decorator可以用来扩展一个对象。

它实现的方法是新建一个类,这个类和原来的类属于同一个接口。然后这个类接受一个原来的类的对象,每个方法都调用原来的类的方法。

如果套用c++的《设计模式》,我们有

class OriginalClass:
	def get_text(self):
		pass
	def get_number(self):
		pass

    
class Decorator:
	def __init__(self, decorated_obj):
		self.decorated_obj = decorated_obj
	def get_text(self):
		return f'<b>{self.decorated_obj.get_text()}</b>'
	def get_number(self):
		return self.decorated_obj.get_number()

但是,这里可以用python的__getattr__特性来简化实现。

class Decorator:
	def __init__(self, decorated_obj):
		self.decorated_obj = decorated_obj
	def get_text(self):
		return f'{self.decorated_obj.get_text()}'
	def __getattr__(self, attr_name):
		return getattr(self.decorated_obj, attr_name)

总结

Sebastian指出,python非常灵活。和25年前的C++大相径庭。很多地方,都非常容易插入逻辑。过去的设计模式,可能并不适用了。我们应该很好的了解python,并借鉴其他语言,而不是生搬硬套。

我觉得,再好的东西,也要和实际相结合。任何脱离实际的做法,都是多余的,甚至有害的。任何理论,方法的产生,都有当时的历史背景,技术背景。如果不了解背后的机制,不了解背后的精神和目的,而是专注于招式本身,那只能是越来越僵化。看似坚持,实际上是背叛。坚持是说固执的坚持原来的做法,背叛是指背叛了初衷。

参考

[1] Why You Don't Need Design Patterns in Python

[2] Design Patterns ? Elements of Reusable Object-Oriented Software

到此这篇关于详解Python为什么不用设计模式的文章就介绍到这了,更多相关Python设计模式内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python判断字符串是否纯数字的方法
Nov 19 Python
mysql 之通过配置文件链接数据库
Aug 12 Python
python随机取list中的元素方法
Apr 08 Python
python网络应用开发知识点浅析
May 28 Python
python 标准差计算的实现(std)
Jul 29 Python
Python提取PDF内容的方法(文本、图像、线条等)
Sep 25 Python
python 定义类时,实现内部方法的互相调用
Dec 25 Python
python 画条形图(柱状图)实例
Apr 24 Python
python异步Web框架sanic的实现
Apr 27 Python
Python如何实现爬取B站视频
May 20 Python
Python astype(np.float)函数使用方法解析
Jun 08 Python
Python 读取位于包中的数据文件
Aug 07 Python
linux中nohup和后台运行进程查看及终止
Jun 24 #Python
Python面向对象之成员相关知识总结
Jun 24 #Python
Python面向对象之内置函数相关知识总结
Jun 24 #Python
python面向对象版学生信息管理系统
Python实现学生管理系统(面向对象版)
Jun 24 #Python
Pycharm连接远程服务器并远程调试的全过程
Python函数中的不定长参数相关知识总结
Jun 24 #Python
You might like
火车头采集器3.0采集图文教程
2007/03/17 PHP
PHP缓冲区用法总结
2016/02/14 PHP
javascript 页面划词搜索JS
2009/09/28 Javascript
JQuery 网站换肤功能实现代码
2009/11/02 Javascript
完美解决AJAX跨域问题
2013/11/01 Javascript
jQuery实现鼠标划过添加和删除class的方法
2015/06/26 Javascript
bootstrap基础知识学习笔记
2016/11/02 Javascript
简单实现node.js图片上传
2016/12/18 Javascript
angular.extend方法的具体使用
2017/09/14 Javascript
vue router demo详解
2017/10/13 Javascript
JS实现的JSON数组去重算法示例
2018/04/11 Javascript
ES6知识点整理之函数对象参数默认值及其解构应用示例
2019/04/17 Javascript
Vue.js轮播图走马灯代码实例(全)
2019/05/08 Javascript
VUEX-action可以修改state吗
2019/11/19 Javascript
js实现无刷新监听URL的变化示例代码详解
2020/06/03 Javascript
快速解决element的autofocus失效问题
2020/09/08 Javascript
[02:41]《西雅图我们来了》2015国际邀请赛出征全记录
2015/07/23 DOTA
[19:26]TNC vs EG (BO3)
2018/06/07 DOTA
[36:33]完美世界DOTA2联赛PWL S2 LBZS vs Forest 第二场 11.29
2020/12/02 DOTA
Python中AND、OR的一个使用小技巧
2015/02/18 Python
Python中断言Assertion的一些改进方案
2016/10/27 Python
利用python实现微信头像加红色数字功能
2018/03/26 Python
python日期时间转为字符串或者格式化输出的实例
2018/05/29 Python
python正则表达式之对号入座篇
2018/07/24 Python
python opencv实现旋转矩形框裁减功能
2018/07/25 Python
python利用跳板机ssh远程连接redis的方法
2019/02/19 Python
详解Django自定义图片和文件上传路径(upload_to)的2种方式
2020/12/01 Python
HTML5 video标签(播放器)学习笔记(二):播放控制
2015/04/24 HTML / CSS
在html页面中取得session中的值的方法
2020/08/11 HTML / CSS
J2SDK1.5与J2SDK5.0有什么区别
2012/09/19 面试题
简述索引存取方法的作用和建立索引的原则
2013/03/26 面试题
大学生学习生活的自我评价
2013/11/01 职场文书
安全生产先进个人总结
2015/02/15 职场文书
2015年九一八事变纪念活动实施方案
2015/05/06 职场文书
2016年社区服务活动总结
2016/04/06 职场文书
nginx 多个location转发任意请求或访问静态资源文件的实现
2021/03/31 Servers