详解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操作日期和时间的方法
Mar 11 Python
Python中数字以及算数运算符的相关使用
Oct 12 Python
网站渗透常用Python小脚本查询同ip网站
May 08 Python
Python实现PS滤镜碎片特效功能示例
Jan 24 Python
初探TensorFLow从文件读取图片的四种方式
Feb 06 Python
在windows下Python打印彩色字体的方法
May 15 Python
Python实现快速傅里叶变换的方法(FFT)
Jul 21 Python
python如何解析复杂sql,实现数据库和表的提取的实例剖析
May 15 Python
基于python 取余问题(%)详解
Jun 03 Python
python request 模块详细介绍
Nov 10 Python
python 基于selenium实现鼠标拖拽功能
Dec 24 Python
解决Pytorch修改预训练模型时遇到key不匹配的情况
Jun 05 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
关于我转生变成史莱姆这档事:第二季PV上线,萌王2021年回归
2020/05/06 日漫
php set_time_limit()函数的使用详解
2013/06/05 PHP
php 表单提交大量数据发生丢失的解决方法
2014/03/03 PHP
Windows7下的php环境配置教程
2015/02/28 PHP
PHP常用的排序和查找算法
2015/08/06 PHP
php 广告点击统计代码(php+mysql)
2018/02/21 PHP
PHP安装扩展mcrypt以及相关依赖项深入讲解
2021/03/04 PHP
JavaScript 常用函数
2009/12/30 Javascript
解决Extjs上传图片无法预览的解决方法
2012/03/22 Javascript
Javascript处理DOM元素事件实现代码
2012/05/23 Javascript
原生js实现shift/ctrl/alt按键的获取
2013/04/08 Javascript
JavaScript String.replace函数参数实例说明
2013/06/06 Javascript
在JS数组特定索引处指定位置插入元素
2014/07/27 Javascript
jQuery晃动层特效实现方法
2015/03/09 Javascript
js验证框架实现代码分享
2016/05/18 Javascript
使用Curl命令查看请求响应时间方法
2016/11/04 Javascript
Ajax验证用户名或昵称是否已被注册
2017/04/05 Javascript
关于webpack代码拆分的解析
2017/07/20 Javascript
vue组件Prop传递数据的实现示例
2017/08/17 Javascript
一文让你彻底搞清楚javascript中的require、import与export
2017/09/24 Javascript
JS运动特效之同时运动实现方法分析
2018/01/24 Javascript
详解Koa中更方便简单发送响应的方式
2018/07/20 Javascript
javascript网页随机点名实现过程解析
2019/10/15 Javascript
JS数组方法concat()用法实例分析
2020/01/18 Javascript
九步学会Python装饰器
2015/05/09 Python
对python中的高效迭代器函数详解
2018/10/18 Python
详解Python中打乱列表顺序random.shuffle()的使用方法
2019/11/11 Python
Pandas的Apply函数具体使用
2020/07/21 Python
KIKO美国官网:意大利的平价彩妆品牌
2017/05/16 全球购物
DogBuddy荷兰:找到你最完美的狗保姆
2019/04/17 全球购物
客服专员岗位职责范本
2013/11/29 职场文书
交通事故赔偿协议书
2014/04/15 职场文书
2014年质量管理工作总结
2014/12/01 职场文书
信用卡催款律师函
2015/05/27 职场文书
2016年百日安全生产活动总结
2016/04/06 职场文书
详解Laravel制作API接口
2021/05/31 PHP