Python中的函数式编程:不可变的数据结构
作者:Moshe Zadka 发布时间:2023-09-05 07:16:35
让我们首先考虑正方形和长方形。如果我们认为在接口方面,忽略了实现细节,方块是否是矩形的子类型?
子类型的定义取决于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
在这篇文章中,我们了解了为什么不变性对于思考我们的代码是有用的,以及如何在没有昂贵的性能代价的情况下实现它。
来源:https://opensource.com/article/18/10/functional-programming-python-immutable-data-structures


猜你喜欢
- 查看依赖包及对应的版本号信息的方法有两种:方法1:pip list 方法2:pip freeze这两个同时适用于Windows和Linux系
- 需要写个js滑动展开折叠(收缩)的效果,搜索到无忧脚本的一篇贴子,稍加修改了下使其在FF也可应用,代码如下: <
- 前言我的 App 项目的 API 部分是使用 Django REST Framework 来搭建的,它可以像搭积木一样非常方便地搭出 API
- 1.选择File -> Settings2.选择 File and Code Templates -> Files ->
- 本文实例讲述了flask框架实现连接sqlite3数据库的方法。分享给大家供大家参考,具体如下:1. 在flask文件夹中新建一个model
- 变量全都是引用跟其他编程语言不同,Python的变量不是盒子,不会存储数据,它们只是引用,就像标签一样,贴在对象上面。比如:>>
- 模板的继承完美在写html的时候会发现,自己多个html文件中又好多东西是一样的,包括静插件的引入 还有有些简单的css样式都不需要修改,这
- 环境与开发工具在抓包的时候,开始使用的是Chrome开发工具中的Network,结果没有抓到,后来使用Fiddler成功抓取数据。下面逐步来
- 如何在线压缩Access数据库?Access数据库可以在线压缩吗?可以的,代码和说明见下:compact.asp<%option&nb
- 前言在本文中,我们将介绍10个示例,以掌握如何使用用于Python的Seaborn库创建图表。任何数据产品的第一步都应该是理解原始数据。对于
- 看到这个标题,你我可能都笑了。你会笑,因为你以为这个东西太小儿科了,还用得着做一个标题?!我会笑,是因为我确信你看完后会改变你的想法。首先我
- 1、登录接口登录后返回对应token封装:import jsonimport requestsfrom util.operation_jso
- 您也可以提供几个连接字符串修饰符来控制连接池行为,请参见本主题内下文中“使用连接字符串关键字控制连接池”这一节。池的创建和分配当连接打开时,
- 简单替代密码简单替换密码是最常用的密码,包括为每个密文文本字符替换每个纯文本字符的算法.在这个过程中,与凯撒密码算法相比,字母表是混乱的.示
- 最近一直在做Dnn模块的开发,过程中碰到这么一个问题,需要同时插入N条数据,不想在程序里控制,但是SQL Sever又不支持数组参数.所以只
- MYSQLdump参数详解mysqldump备份:mysqldump -u用户名 -p密码 -h主机 数据库 a -w “sql条件” –l
- 在本文中,我们将介绍 Python 中 _ 字符的不同用法。就像 Python 中的许多其他内容一样,我们会看到 “_” 的不同用法主要是惯
- 在django项目根目录位置创建scrapy项目,django_12是django项目,ABCkg是scrapy爬虫项目,app1是djan
- 在CSS样式中,dl部分只是简单的把内外边距设置为0,dd部分有一个clear属性需要特别注意。当某个元素的属性设置float浮动时,它所在
- 本文介绍了用ASP的AdoDb.Stream读取/写入UTF-8编码格式的文件的方法:函数名称:ReadTextFile 作用:利用AdoD