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读csv文件去掉一列后再写入新的文件实例
Dec 28 Python
学习Python selenium自动化网页抓取器
Jan 20 Python
python正则表达式爬取猫眼电影top100
Feb 24 Python
用pandas中的DataFrame时选取行或列的方法
Jul 11 Python
Python Threading 线程/互斥锁/死锁/GIL锁
Jul 21 Python
python爬虫豆瓣网的模拟登录实现
Aug 21 Python
对python while循环和双重循环的实例详解
Aug 23 Python
django实现类似触发器的功能
Nov 15 Python
13个Pandas实用技巧,助你提高开发效率
Aug 19 Python
python 下划线的不同用法
Oct 24 Python
python+flask编写一个简单的登录接口
Nov 13 Python
python给list排序的简单方法
Dec 10 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使用正则表达式清除超链接文本
2013/11/12 PHP
php导出csv数据在浏览器中输出提供下载或保存到文件的示例
2014/04/24 PHP
PHP实现的mysql主从数据库状态检测功能示例
2017/07/20 PHP
PHP实现webshell扫描文件木马的方法
2017/07/31 PHP
PHP如何通过带尾指针的链表实现'队列'
2020/10/22 PHP
让网页根据不同IE版本显示不同的内容
2009/02/08 Javascript
jQuery on方法传递参数示例
2014/12/09 Javascript
Js实现自定义右键行为
2015/03/26 Javascript
JQuery显示、隐藏div的几种方法简明总结
2015/04/16 Javascript
javascript伸缩型菜单实现代码
2015/11/16 Javascript
谈一谈javascript中继承的多种方式
2016/02/19 Javascript
Bootstrap每天必学之按钮(Button)插件
2016/04/25 Javascript
原生JavaScript编写canvas版的连连看游戏
2016/05/29 Javascript
使用Promise链式调用解决多个异步回调的问题
2017/01/15 Javascript
Node.js Mongodb 密码特殊字符 @的解决方法
2017/04/11 Javascript
nodejs批量下载图片的实现方法
2017/05/19 NodeJs
静态页面实现 include 引入公用代码的示例
2017/09/25 Javascript
详解webpack babel的配置
2018/01/09 Javascript
vuex提交state&amp;&amp;实时监听state数据的改变方法
2018/09/16 Javascript
在element-ui的select下拉框加上滚动加载
2019/04/18 Javascript
微信小程序实现点击效果
2019/06/21 Javascript
[01:13:59]LGD vs Mineski Supermajor 胜者组 BO3 第三场 6.5
2018/06/06 DOTA
学习python的几条建议分享
2013/02/10 Python
Python计算开方、立方、圆周率,精确到小数点后任意位的方法
2018/07/17 Python
Python-opencv实现红绿两色识别操作
2020/06/04 Python
input元素的url类型和email类型简介
2012/07/11 HTML / CSS
什么是SQL Server的确定性函数和不确定性函数
2016/08/04 面试题
在对linux系统分区进行格式化时需要对磁盘簇(或i节点密度)的大小进行选择,请说明选择的原则
2012/11/24 面试题
校长先进事迹材料
2014/02/01 职场文书
公司市场专员岗位职责
2014/06/29 职场文书
音乐幼师求职信
2014/07/09 职场文书
服务员态度差检讨书
2014/10/28 职场文书
优秀员工推荐材料
2014/12/20 职场文书
电影雷锋观后感
2015/06/10 职场文书
python编写函数注意事项总结
2021/03/29 Python
Python破解极验滑动验证码详细步骤
2021/05/21 Python