Vấn đề
Cần triển khai immutable data structures trong Python.
Giới thiệu
Immutable data structures rất tiện khi muốn ngăn nhiều người sửa cùng một dữ liệu trong lập trình song song. Mutable (ví dụ Array) có thể thay đổi bất kỳ lúc nào, immutable thì không.
Cách làm
Demo từng bước xử lý immutable vs mutable.
Ví dụ
# STEP 01 - Tạo Mutable array
atp_players = ['Murray', 'Nadal', 'Djokovic']
print(f\" *** Original Data in my array is - {atp_players}\")*** Original Data in my array is -
['Murray', 'Nadal', 'Djokovic']# Thay đổi tên cầu thủ Murray -> Federer
atp_players[0] = 'Federer'
print(f\" *** Modified Data in my array is - {atp_players}\")*** Modified Data in my array is -
['Federer', 'Nadal', 'Djokovic']Kết luận
Đã thay đổi giá trị mảng dễ dàng, hữu ích nếu bạn là người dùng duy nhất. Tuy nhiên, thực tế nhiều chương trình dùng mảng này → dữ liệu bất ngờ.
Tuple hành xử khác, xem ví dụ:
# STEP 02 - Thử thay đổi Tuple
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 assignmentKết luận: Tuple không thể sửa đổi. Tuy nhiên có ngoại lệ: nếu tuple chứa mảng, giá trị mảng có thể thay đổi.
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'])Cách bảo vệ dữ liệu? Chuyển mảng thành tuple.
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 assignmentPython có công cụ tuyệt vời: NamedTuple. Là class để tạo constructor. Hiểu qua code:
# Tạo class đơn giản Grandslam titles Python way
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 - 20Class này immutable? Thử đổi Federer -> Nadal.
stats.player = 'Nadal'
print(f\" *** Stats has details as {stats.player} - {stats.titles}\")*** Stats has details as Nadal - 20Không ngạc nhiên, nó mutable vì cập nhật được. Tạo class với NamedTuple xem mặc định:
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: can't set attributeDjokovic phải đợi thêm để đạt 20 Grand Slam.
Tuy có thể dùng _replace để tạo bản sao và cập nhật giá trị:
djokovic_stats = stats._replace(player=\"Djokovic\", titles=17)
print(f\" *** djokovic_stats has details as {djokovic_stats.player} - {djokovic_stats.titles}\")*** djokovic_stats has details as Djokovic - 17Ví dụ tổng hợp
Giả lập phần mềm cửa hàng rau.
from typing import Tuple, NamedTuple
# Class đại diện một mặt hàng
class Prices(NamedTuple):
id: int
name: str
price: int # Price in dollars
# Class theo dõi đơn hàng
class Purchase(NamedTuple):
purchase_id: int
items: Tuple[Prices]
# Tạo mặt hàng và giá
carrot = Prices(1, \"carrot\", 2)
tomato = Prices(2, \"tomato\", 3)
eggplant = Prices(3, \"eggplant\", 5)
# Khách hàng Mr.Tom mua cà rốt và cà chua
tom_order = Purchase(1, (carrot, tomato))
# Tính tổng tiền
total_cost = sum(item.price for item in tom_order.items)
print(f\"*** Total Cost from Mr.Tom is - {total_cost}$\")Output
*** Total Cost from Mr.Tom is - 5$