Python中的函数式编程:不可变的数据结构


Posted in Python onOctober 08, 2018

让我们首先考虑正方形和长方形。如果我们认为在接口方面,忽略了实现细节,方块是否是矩形的子类型?

子类型的定义取决于Liskov代换原理。为了成为一个子类型,它必须能够完成超级类型所做的一切。

如何定义矩形的接口?

zope.interface import Interface
class IRectangleInterface:
get_length:
"""Squares can do that"""
get_width:
"""Squares can do that"""
set_dimensions length width:
"""Uh oh"""

如果这是定义,则方块不能是矩形的子类型;它们不能响应set_dimensions方法,如果长度和宽度不同。

另一种方法是选择制作矩形。不变.

class IRectangleInterface:
get_length:
"""Squares can do that"""
get_width:
"""Squares can do that"""
with_dimensions length width:
"""Returns a new rectangle"""

现在,一个正方形可以是一个矩形。它可以返回一个新的矩形(通常不是正方形)with_dimensions被称为,但它不会停止成为一个正方形。

这似乎是一个学术问题-直到我们考虑到,从某种意义上说,正方形和长方形是它们两边的容器。在我们理解了这个例子之后,更实际的情况是使用更传统的容器。例如,考虑随机访问数组.

我们有ISquare和IRectangle,和ISquare是IRectangle.

我们希望在随机访问数组中放置矩形:

class IArrayOfRectanglesInterface:
get_element i:
"""Returns Rectangle"""
set_element i rectangle:
"""'rectangle' can be any IRectangle"""

我们也想把正方形放在一个随机存取数组中:

class IArrayOfSquareInterface:
get_element i:
"""Returns Square"""
set_element i square:
"""'square' can be any ISquare"""

即使ISquare是IRectangle,任何数组都不能实现这两者。IArrayOfSquare和IArrayOfRectangle.

为什么不行?假设bucket实现两者。

>>> rectangle make_rectangle 
>>> bucket.set_element rectangle # This is allowed by IArrayOfRectangle
>>> thing bucket.get_element # That has to be a square by IArrayOfSquare
>>> assert thing.height thing.width
Traceback most recent call last:
File "<stdin>" line module
AssertionError

两者都不能实现,这意味着两者都不是另一种类型的子类型,尽管ISquare是IRectangle。问题是set_element方法:如果我们有一个只读数组,IArrayOfSquare的子类型IArrayOfRectangle.

可变性,都是可变的。IRectangle接口和可变IArrayOf接口使得对类型和子类型的思考变得更加困难-而放弃的能力意味着我们期望类型之间的直观关系实际上仍然有效。

突变也可以非局部效果。当两个地方之间的共享对象被一个突变时,就会发生这种情况。典型的例子是一个线程与另一个线程交互一个共享对象,但是即使在一个单线程程序中,在相距很远的地方之间共享也很容易。考虑到在Python中,大多数对象都可以从许多地方访问:作为一个模块全局,或者在堆栈跟踪中,或者作为一个类属性。

如果我们不能限制共享,我们可能会考虑限制可变。

下面是一个不可变的矩形,它利用AutoS库:

attr.frozen
class Rectangeobject:
length attr.
width attr.
classmethod
with_dimensionscls length width:
return clslength width

这里是一个正方形:

attr.frozen
class Squareobject:
side attr.
classmethod
with_dimensionscls length width:
return Rectanglelength width

使用frozen参数,我们可以很容易地创建一个不可变的类。所有艰苦的写作工作__setitem__正确的做法是别人做的,对我们来说是完全看不见的。

修改对象仍然是容易的,改变它们几乎是不可能的

too_long Rectangle 
reasonable attr.evolvetoo_long length

可靠的包装允许我们有不可变的容器

# Vector of integers
a = pyrsistent.v(1, 2, 3)
# Not a vector of integers
b = a.set(1, "hello")

当b不是整数的向量,任何东西都不会停止。a从成为一个。

万一a一百万个元素长了吗?是b要复制999 999份吗?Pyrsistent附带“大O”性能保证:所有操作都采用O(log n)时间到了。它还附带了一个可选的C扩展,以提高性能超越大O。

为了修改嵌套对象,它附带了“转换器”的概念:

blog pyrsistent.
title"My blog"
linkspyrsistent."github" "twitter"
postspyrsistent.
pyrsistent.title"no updates"
content"I'm busy"
pyrsistent.title"still no updates"
content"still busy"
new_blog blog.transform"posts" "content"
"pretty busy"

new_blog将成为不可变的等价物。

'links': 'github' 'twitter'
'posts': 'content': "I'm busy"
'title': 'no updates'
'content': 'pretty busy'
'title': 'still no updates'
'title': 'My blog'

但blog还是一样的。这意味着任何引用旧对象的人都没有受到影响:转换只有本土化效果。

当分享猖獗时,这是有用的。例如,考虑默认参数:

silly_suma b extrav :
extra extra.extenda b
return extra

在这篇文章中,我们了解了为什么不变性对于思考我们的代码是有用的,以及如何在没有昂贵的性能代价的情况下实现它。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。如果你想了解更多相关内容请查看下面相关链接

Python 相关文章推荐
简单讲解Python中的数字类型及基本的数学计算
Mar 11 Python
用python实现的线程池实例代码
Jan 06 Python
python中set()函数简介及实例解析
Jan 09 Python
influx+grafana自定义python采集数据和一些坑的总结
Sep 17 Python
Python一句代码实现找出所有水仙花数的方法
Nov 13 Python
在Qt中正确的设置窗体的背景图片的几种方法总结
Jun 19 Python
Python正则表达式匹配数字和小数的方法
Jul 03 Python
python对常见数据类型的遍历解析
Aug 27 Python
pyftplib中文乱码问题解决方案
Jan 11 Python
Django 博客实现简单的全文搜索的示例代码
Feb 17 Python
tensorflow从ckpt和从.pb文件读取变量的值方式
May 26 Python
使用python求斐波那契数列中第n个数的值示例代码
Jul 26 Python
详解多线程Django程序耗尽数据库连接的问题
Oct 08 #Python
JSON文件及Python对JSON文件的读写操作
Oct 07 #Python
Python实现登陆文件验证方法
Oct 06 #Python
python对日志进行处理的实例代码
Oct 06 #Python
浅析Python函数式编程
Oct 06 #Python
Python实现iOS自动化打包详解步骤
Oct 03 #Python
Python中GIL的使用详解
Oct 03 #Python
You might like
php面向对象全攻略 (九)访问类型
2009/09/30 PHP
无法在发生错误时创建会话,请检查 PHP 或网站服务器日志,并正确配置 PHP 安装最快的解决办法
2010/08/01 PHP
php中获得视频时间总长度的另一种方法
2011/09/15 PHP
ThinkPHP自动填充实现无限级分类的方法
2014/08/22 PHP
PHP网站开发中常用的8个小技巧
2015/02/13 PHP
php实现的通用图片处理类
2015/03/24 PHP
Yii2简单实现多语言配置的方法
2016/07/23 PHP
Jquery AJAX 框架的使用方法
2009/11/03 Javascript
JavaScript isPrototypeOf和hasOwnProperty使用区别
2010/03/04 Javascript
javascript中万恶的function实例分析
2011/05/25 Javascript
JAVASCRIPT车架号识别/验证函数代码 汽车车架号验证程序
2012/01/08 Javascript
javascript 系统文件夹文件操作及参数介绍
2013/01/08 Javascript
JS实现程序暂停与继续功能代码解读
2013/10/10 Javascript
javascript检查浏览器是否支持flash的实现代码
2014/08/14 Javascript
jQuery $命名冲突解决方案汇总
2014/11/13 Javascript
js控制页面的全屏展示和退出全屏显示的方法
2015/03/10 Javascript
jQuery插件扩展实例【添加回调函数】
2016/11/26 Javascript
微信小程序动态设置图片大小的方法
2019/11/21 Javascript
[01:29:46]DOTA2上海特级锦标赛C组资格赛#1 OG VS LGD第二局
2016/02/27 DOTA
Python中使用PyQt把网页转换成PDF操作代码实例
2015/04/23 Python
win与linux系统中python requests 安装
2016/12/04 Python
使用Python获取网段IP个数以及地址清单的方法
2018/11/01 Python
Django框架orM与自定义SQL语句混合事务控制操作
2019/06/27 Python
Django获取model中的字段名和字段的verbose_name方式
2020/05/19 Python
在tensorflow以及keras安装目录查询操作(windows下)
2020/06/19 Python
详解numpy1.19.4与python3.9版本冲突解决
2020/12/15 Python
机关党员2014全国两会学习心得体会
2014/03/10 职场文书
党支部公开承诺践诺书
2014/03/28 职场文书
单位接收函格式
2015/01/30 职场文书
搞笑婚前保证书
2015/02/28 职场文书
拾金不昧通报表扬范文
2015/05/05 职场文书
毕业生自我鉴定范文
2019/05/13 职场文书
生鲜超市—未来中国最具有潜力零售业态
2019/08/02 职场文书
导游词之太行山青龙峡
2020/01/14 职场文书
Windows10下安装MySQL8
2021/04/06 MySQL
MySQL图形化管理工具Navicat安装步骤
2021/12/04 MySQL