如何在 Python 中实现不可变数据结构?
问题
您需要在 Python 中实现不可变数据结构。
简介..
当您想要防止多个人同时在并行编程中修改一段数据时,不可变数据结构非常方便。可变数据结构(例如数组)可以随时更改,而不可变数据结构则不能。
如何做到这一点..
让我一步一步向您展示如何处理不可变和可变数据结构。
示例
# 步骤 01 - 创建可变数组。
# 定义一个数组
atp_players = ['Murray', 'Nadal', 'Djokovic']
print(f" *** Original Data in my array is - {atp_players}")
*** 我的数组中的原始数据是 -
['Murray', 'Nadal', 'Djokovic']
# 将球员姓名从 Murray 改为 Federer
atp_players[0] = 'Federer'
print(f" *** Modified Data in my array is - {atp_players}")
*** 修改后的数组数据为 -
['Federer', 'Nadal', 'Djokovic']
结论
我们已经能够像这样更改数组值,如果您是此数组的独家用户,这可能会很有用。然而,在实时生产中,多个程序可能会使用此数组进行更改,并可能导致意外数据。
另一方面,元组的行为略有不同,请看下面的示例。
# 步骤 02 - 尝试更改元组
try:
atp_players_tuple = ('Murray', 'Nadal', 'Djokovic')
print(f" *** Original Data in my tuple is - {atp_players_tuple}")
atp_players_tuple[0] = 'Federer'
except Exception as error:
print(f" *** Tried modifying data but ended up with - {error}")
*** Original Data in my tuple is - ('Murray', 'Nadal', 'Djokovic')
*** Tried modifying data but ended up with - 'tuple' object does not support item assignment
结论:
上面您看到的是,元组不能被修改,对吗?但是有一个例外,如果元组中有数组,则可以更改其值。
atp_players_array_in_tuple = (['Murray'], ['Nadal'], ['Djokovic'])
print(f" *** Original Data in my tuple with arrays is - {atp_players_array_in_tuple}")
atp_players_array_in_tuple[0][0] = 'Federer'
print(f" *** Modified Data in my tuple with arrays is - {atp_players_array_in_tuple}")
*** Original Data in my tuple with arrays is - (['Murray'], ['Nadal'], ['Djokovic']) *** Modified Data in my tuple with arrays is - (['Federer'], ['Nadal'], ['Djokovic'])
那么如何保护数据呢?嗯,只需将数组转换为元组即可。
try:
atp_players_tuple_in_tuple = (('Murray'), ('Nadal'), ('Djokovic'))
print(f" *** Original Data in my tuple is - {atp_players_tuple_in_tuple}")
atp_players_tuple_in_tuple[0] = 'Federer'
except Exception as error:
print(f" *** Tried modifying data in my tuple but ended up with - {error}")
*** Original Data in my tuple is - ('Murray', 'Nadal', 'Djokovic')
*** Tried modifying data in my tuple but ended up with - 'tuple' object does not support item assignment
还有更多... Python 有一个很棒的内置工具,名为 NamedTuple。它是一个可以扩展以创建构造函数的类。让我们通过编程来理解。
# 以 Python 方式创建 Grandslam 标题的简单类。
class GrandSlamsPythonWay:
def __init__(self, player, titles):
self.player = player
self.titles = titles
stats = GrandSlamsPythonWay("Federer", 20)
print(f" *** Stats has details as {stats.player} - {stats.titles}")
*** Stats has details as Federer - 20
您觉得这个类怎么样?它是不可变的吗?让我们通过将 Federer 更改为 Nadal 来检查一下。
stats.player = 'Nadal'
print(f" *** Stats has details as {stats.player} - {stats.titles}")
*** Stats has details as Nadal - 20
因此,毫不奇怪它是一个不可变的数据结构,因为我们能够将 Federer 更新为 Nadal。现在让我们创建一个带有 NamedTuple 的类,看看它的默认行为是什么。
from typing import NamedTuple
class GrandSlamsWithNamedTuple(NamedTuple):
player: str
titles: int
stats = GrandSlamsWithNamedTuple("Federer", 20)
print(f" *** Stats has details as {stats.player} - {stats.titles}")
stats.player = 'Djokovic'
print(f" *** Stats has details as {stats.player} - {stats.titles}")
*** Stats has details as Federer - 20
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
in
10 print(f" *** Stats has details as {stats.player} - {stats.titles}")
11
---> 12 stats.player = 'Djokovic'
13 print(f" *** Stats has details as {stats.player} - {stats.titles}")
AttributeError: can't set attribute
看来德约科维奇还得再等一段时间才能获得 20 个大满贯冠军。
但是,我们可以使用 _replace 方法进行复制并在 _replace 期间更新值。
djokovic_stats = stats._replace(player="Djokovic", titles=17)
print(f" *** djokovic_stats has details as {djokovic_stats.player} - {djokovic_stats.titles}")
*** djokovic_stats 的详细信息为 Djokovic - 17
示例
最后,我将举一个例子,涵盖上面解释的所有内容。
对于这个例子,假设我们正在为蔬菜店编写软件。
from typing import Tuple
# 创建一个类来表示一次购买
class Prices(NamedTuple):
id: int
name: str
price: int # 价格(美元)
# 创建一个类来跟踪购买
class Purchase(NamedTuple):
purchase_id: int
items: Tuple[Prices]
# 创建蔬菜项目及其相应的价格
carrot = Prices(1, "carrot", 2)
tomato = Prices(2, "tomato", 3)
eggplant = Prices(3, "eggplant", 5)
# 现在假设我们的第一位顾客汤姆先生购买了胡萝卜和西红柿
tom_order = Purchase(1, (carrot, tomato))
# 知道我们需要向汤姆先生收取的总费用
total_cost = sum(item.price for item in tom_order.items)
print(f"*** Total Cost from Mr.Tom is - {total_cost}$")
输出
*** Total Cost from Mr.Tom is - 5$
有用资源
python 参考教程 - 该教程包含有关 python 的更多信息:https://www.cainiaomax.com/python/

