详解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获取GY-85九轴模块信息示例
Dec 05 Python
简单总结Python中序列与字典的相同和不同之处
Jan 19 Python
Python实现获取磁盘剩余空间的2种方法
Jun 07 Python
python中datetime模块中strftime/strptime函数的使用
Jul 03 Python
Python 2.7中文显示与处理方法
Jul 16 Python
Python实现的逻辑回归算法示例【附测试csv文件下载】
Dec 28 Python
详解python中sort排序使用
Mar 23 Python
Python 编程速成(推荐)
Apr 15 Python
python异步实现定时任务和周期任务的方法
Jun 29 Python
Python3离线安装Requests模块问题
Oct 13 Python
使用Python爬虫库requests发送表单数据和JSON数据
Jan 25 Python
python 使用三引号时容易犯的小错误
Oct 21 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
星际争霸 Starcraft 发展史
2020/03/14 星际争霸
php页面缓存方法小结
2015/01/10 PHP
PHP截取IE浏览器并缩小原图的方法
2016/03/04 PHP
yii2中关于加密解密的那些事儿
2018/06/12 PHP
yii 框架实现按天,月,年,自定义时间段统计数据的方法分析
2020/04/04 PHP
让浏览器非阻塞加载javascript的几种方法小结
2011/04/25 Javascript
常见效果实现之返回顶部(结合淡入、淡出、减速滚动)
2012/01/04 Javascript
用js判断页面刷新或关闭的方法(onbeforeunload与onunload事件)
2012/06/22 Javascript
js控制表单奇偶行样式的简单方法
2013/07/31 Javascript
基于Node.js实现nodemailer邮件发送
2016/01/26 Javascript
深入浅析Bootstrap列表组组件
2016/05/03 Javascript
基于百度地图实现产品销售的单位位置查看功能设计与实现
2016/10/21 Javascript
JS中作用域和变量提升(hoisting)的深入理解
2016/10/31 Javascript
详解基于webpack和vue.js搭建开发环境
2017/04/05 Javascript
详解Angular 4.x NgTemplateOutlet
2017/05/24 Javascript
详解vue-resource promise兼容性问题
2017/06/20 Javascript
手动用webpack搭建第一个ReactApp的示例
2018/04/11 Javascript
对vuejs的v-for遍历、v-bind动态改变值、v-if进行判断的实例讲解
2018/08/27 Javascript
详解vue 项目白屏解决方案
2018/10/31 Javascript
如何在 Vue 中使用 JSX
2021/02/14 Vue.js
利用Python检测URL状态
2019/07/31 Python
python监控nginx端口和进程状态
2019/09/06 Python
基于python的列表list和集合set操作
2019/11/24 Python
python获取array中指定元素的示例
2019/11/26 Python
Pytorch转keras的有效方法,以FlowNet为例讲解
2020/05/26 Python
python Selenium 库的使用技巧
2020/10/16 Python
Python列表元素删除和remove()方法详解
2021/01/04 Python
营销主管自我评价怎么写
2013/09/19 职场文书
技术总监个人的自我评价范文
2013/12/18 职场文书
水电站项目建议书
2014/05/12 职场文书
党支部活动策划方案
2014/08/18 职场文书
班子个人四风问题整改措施
2014/10/04 职场文书
幼儿园教师师德师风承诺书
2015/04/28 职场文书
奖学金主要事迹范文
2015/11/04 职场文书
基于Golang 高并发问题的解决方案
2021/05/08 Golang
关于springboot配置druid数据源不生效问题(踩坑记)
2021/09/25 Java/Android