Python中的函數式編程:不可變的數據結構

今天小編就爲大家分享一篇關於Python中的函數式編程:不可變的數據結構,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
讓我們首先考慮正方形和長方形。如果我們認爲在接口方面,忽略了實現細節,方塊是否是矩形的子類型?

子類型的定義取決於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零基礎到項目實戰的資料,每天給大家講解python最新的技術,前景,學習需要留言的小細節
總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章