Bài 10.4. Python - Lưu trữ dữ liệu

Bài 10.4. Python - Lưu trữ dữ liệu
Nhiều chương trình của bạn sẽ yêu cầu người dùng nhập một số loại thông tin. Bạn có thể cho phép người dùng lưu trữ các tùy chọn trong một trò chơi hoặc cung cấp dữ liệu cho một hình ảnh hóa. Dù trọng tâm của chương trình của bạn là gì, bạn sẽ lưu trữ thông tin mà người dùng cung cấp trong các cấu trúc dữ liệu như danh sách và từ điển. Khi người dùng đóng chương trình, bạn sẽ gần như luôn muốn lưu thông tin mà họ đã nhập. Một cách đơn giản để làm điều này là sử dụng module json
.
Module json
cho phép bạn chuyển đổi các cấu trúc dữ liệu Python đơn giản thành các chuỗi định dạng JSON, và sau đó tải dữ liệu từ tệp đó vào lần tiếp theo chương trình chạy. Bạn cũng có thể sử dụng json
để chia sẻ dữ liệu giữa các chương trình Python khác nhau. Thậm chí tốt hơn, định dạng dữ liệu JSON không chỉ dành riêng cho Python, vì vậy bạn có thể chia sẻ dữ liệu bạn lưu trữ trong định dạng JSON với những người làm việc trong nhiều ngôn ngữ lập trình khác. Đó là một định dạng hữu ích và di động, và dễ học.
Sử dụng json.dumps()
và json.loads()
Hãy viết một chương trình ngắn lưu trữ một tập hợp các số và một chương trình khác đọc lại các số này vào bộ nhớ. Chương trình đầu tiên sẽ sử dụng json.dumps()
để lưu trữ tập hợp các số, và chương trình thứ hai sẽ sử dụng json.loads()
.
Hàm json.dumps()
nhận một đối số: một mảnh dữ liệu cần được chuyển đổi sang định dạng JSON. Hàm trả về một chuỗi, mà chúng ta có thể ghi vào một tệp dữ liệu:
# filepath: /f:/blog/python-vy/10/number_writer.py
from pathlib import Path
import json
numbers = [2, 3, 5, 7, 11, 13]
path = Path('numbers.json')
contents = json.dumps(numbers)
path.write_text(contents)
Chúng ta đầu tiên nhập module json
, và sau đó tạo một danh sách các số để làm việc. Sau đó, chúng ta chọn một tên tệp để lưu trữ danh sách các số. Thông thường, chúng ta sử dụng phần mở rộng tệp .json
để chỉ ra rằng dữ liệu trong tệp được lưu trữ ở định dạng JSON. Tiếp theo, chúng ta sử dụng hàm json.dumps()
để tạo ra một chuỗi chứa đại diện JSON của dữ liệu mà chúng ta đang làm việc. Khi chúng ta có chuỗi này, chúng ta ghi nó vào tệp bằng phương thức write_text()
mà chúng ta đã sử dụng trước đó.
Chương trình này không có đầu ra, nhưng hãy mở tệp numbers.json
và xem nó. Dữ liệu được lưu trữ ở định dạng trông giống như Python:
[2, 3, 5, 7, 11, 13]
Bây giờ chúng ta sẽ viết một chương trình riêng biệt sử dụng json.loads()
để đọc lại danh sách vào bộ nhớ:
# filepath: /f:/blog/python-vy/10/number_reader.py
from pathlib import Path
import json
path = Path('numbers.json')
contents = path.read_text()
numbers = json.loads(contents)
print(numbers)
Chúng ta đảm bảo đọc từ cùng một tệp mà chúng ta đã ghi vào. Vì tệp dữ liệu chỉ là một tệp văn bản với định dạng cụ thể, chúng ta có thể đọc nó bằng phương thức read_text()
. Sau đó, chúng ta truyền nội dung của tệp vào json.loads()
. Hàm này nhận một chuỗi định dạng JSON và trả về một đối tượng Python (trong trường hợp này là một danh sách), mà chúng ta gán cho numbers
. Cuối cùng, chúng ta in ra danh sách các số đã được khôi phục và thấy rằng nó giống với danh sách được tạo trong number_writer.py
:
[2, 3, 5, 7, 11, 13]
Đây là một cách đơn giản để chia sẻ dữ liệu giữa hai chương trình.
Lưu trữ và đọc dữ liệu do người dùng tạo ra
Lưu trữ dữ liệu bằng json
hữu ích khi bạn làm việc với dữ liệu do người dùng tạo ra, vì nếu bạn không lưu trữ thông tin của người dùng bằng cách nào đó, bạn sẽ mất nó khi chương trình dừng chạy. Hãy xem xét một ví dụ trong đó chúng ta yêu cầu người dùng nhập tên của họ lần đầu tiên họ chạy chương trình và sau đó nhớ tên của họ khi họ chạy chương trình lần sau.
Hãy bắt đầu bằng cách lưu trữ tên của người dùng:
# filepath: /f:/blog/python-vy/10/remember_me.py
from pathlib import Path
import json
username = input("What is your name? ")
path = Path('username.json')
contents = json.dumps(username)
path.write_text(contents)
print(f"We'll remember you when you come back, {username}!")
Chúng ta đầu tiên yêu cầu người dùng nhập tên để lưu trữ. Tiếp theo, chúng ta ghi dữ liệu mà chúng ta vừa thu thập vào một tệp gọi là username.json
. Sau đó, chúng ta in ra một thông báo thông báo cho người dùng rằng chúng ta đã lưu trữ thông tin của họ:
What is your name? Eric
We'll remember you when you come back, Eric!
Bây giờ hãy viết một chương trình mới chào đón một người dùng có tên đã được lưu trữ:
# filepath: /f:/blog/python-vy/10/greet_user.py
from pathlib import Path
import json
path = Path('username.json')
contents = path.read_text()
username = json.loads(contents)
print(f"Welcome back, {username}!")
Chúng ta đọc nội dung của tệp dữ liệu và sau đó sử dụng json.loads()
để gán dữ liệu đã khôi phục cho biến username
. Vì chúng ta đã khôi phục tên người dùng, chúng ta có thể chào đón người dùng trở lại với một lời chào cá nhân hóa:
Welcome back, Eric!
Chúng ta cần kết hợp hai chương trình này thành một tệp. Khi ai đó chạy remember_me.py
, chúng ta muốn khôi phục tên người dùng từ bộ nhớ nếu có thể; nếu không, chúng ta sẽ yêu cầu nhập tên người dùng và lưu trữ nó trong username.json
cho lần sau. Chúng ta có thể viết một khối try-except ở đây để phản hồi phù hợp nếu username.json
không tồn tại, nhưng thay vào đó chúng ta sẽ sử dụng một phương thức tiện lợi từ module pathlib
:
# filepath: /f:/blog/python-vy/10/remember_me.py
from pathlib import Path
import json
path = Path('username.json')
if path.exists():
contents = path.read_text()
username = json.loads(contents)
print(f"Welcome back, {username}!")
else:
username = input("What is your name? ")
contents = json.dumps(username)
path.write_text(contents)
print(f"We'll remember you when you come back, {username}!")
Có nhiều phương thức hữu ích mà bạn có thể sử dụng với các đối tượng Path
. Phương thức exists()
trả về True nếu một tệp hoặc thư mục tồn tại và False nếu không. Ở đây chúng ta sử dụng path.exists()
để tìm hiểu xem một tên người dùng đã được lưu trữ hay chưa. Nếu username.json
tồn tại, chúng ta tải tên người dùng và in ra một lời chào cá nhân hóa cho người dùng.
Nếu tệp username.json
không tồn tại, chúng ta yêu cầu nhập tên người dùng và lưu trữ giá trị mà người dùng nhập. Chúng ta cũng in ra thông báo quen thuộc rằng chúng ta sẽ nhớ họ khi họ quay lại.
Bất kể khối nào được thực thi, kết quả là một tên người dùng và một lời chào phù hợp. Nếu đây là lần đầu tiên chương trình chạy, đây là đầu ra:
What is your name? Eric
We'll remember you when you come back, Eric!
Nếu không:
Welcome back, Eric!
Đây là đầu ra bạn thấy nếu chương trình đã được chạy ít nhất một lần. Mặc dù dữ liệu trong phần này chỉ là một chuỗi đơn, chương trình sẽ hoạt động tốt với bất kỳ dữ liệu nào có thể được chuyển đổi thành một chuỗi định dạng JSON.
Tái cấu trúc
Thường thì bạn sẽ đến một điểm mà mã của bạn sẽ hoạt động, nhưng bạn sẽ nhận ra rằng bạn có thể cải thiện mã bằng cách chia nó thành một loạt các hàm có công việc cụ thể. Quá trình này được gọi là tái cấu trúc. Tái cấu trúc làm cho mã của bạn sạch hơn, dễ hiểu hơn và dễ mở rộng hơn.
Chúng ta có thể tái cấu trúc remember_me.py
bằng cách di chuyển phần lớn logic của nó vào một hoặc nhiều hàm. Trọng tâm của remember_me.py
là chào đón người dùng, vì vậy hãy di chuyển tất cả mã hiện có của chúng ta vào một hàm gọi là greet_user()
:
# filepath: /f:/blog/python-vy/10/remember_me.py
from pathlib import Path
import json
def greet_user():
"""Greet the user by name."""
path = Path('username.json')
if path.exists():
contents = path.read_text()
username = json.loads(contents)
print(f"Welcome back, {username}!")
else:
username = input("What is your name? ")
contents = json.dumps(username)
path.write_text(contents)
print(f"We'll remember you when you come back, {username}!")
greet_user()
Vì chúng ta đang sử dụng một hàm bây giờ, chúng ta viết lại các nhận xét dưới dạng một docstring phản ánh cách chương trình hiện tại hoạt động. Tệp này sạch hơn một chút, nhưng hàm greet_user()
đang làm nhiều hơn chỉ chào đón người dùng - nó cũng đang khôi phục một tên người dùng đã lưu trữ nếu có và yêu cầu nhập một tên người dùng mới nếu không có.
Hãy tái cấu trúc greet_user()
để nó không làm quá nhiều nhiệm vụ khác nhau. Chúng ta sẽ bắt đầu bằng cách di chuyển mã để khôi phục một tên người dùng đã lưu trữ vào một hàm riêng biệt:
# filepath: /f:/blog/python-vy/10/remember_me.py
from pathlib import Path
import json
def get_stored_username(path):
"""Get stored username if available."""
if path.exists():
contents = path.read_text()
username = json.loads(contents)
return username
else:
return None
def greet_user():
"""Greet the user by name."""
path = Path('username.json')
username = get_stored_username(path)
if username:
print(f"Welcome back, {username}!")
else:
username = input("What is your name? ")
contents = json.dumps(username)
path.write_text(contents)
print(f"We'll remember you when you come back, {username}!")
greet_user()
Hàm mới get_stored_username()
có một mục đích rõ ràng, như được nêu trong docstring. Hàm này khôi phục một tên người dùng đã lưu trữ và trả về tên người dùng nếu nó tìm thấy một tên. Nếu đường dẫn được truyền vào get_stored_username()
không tồn tại, hàm trả về None. Đây là một thực hành tốt: một hàm nên trả về giá trị mà bạn mong đợi, hoặc nó nên trả về None. Điều này cho phép chúng ta thực hiện một kiểm tra đơn giản với giá trị trả về của hàm. Chúng ta in ra một thông báo chào đón người dùng trở lại nếu nỗ lực khôi phục một tên người dùng thành công, và nếu không, chúng ta yêu cầu nhập một tên người dùng mới.
Chúng ta nên tách thêm một khối mã ra khỏi greet_user()
. Nếu tên người dùng không tồn tại, chúng ta nên di chuyển mã yêu cầu nhập một tên người dùng mới vào một hàm dành riêng cho mục đích đó:
# filepath: /f:/blog/python-vy/10/remember_me.py
from pathlib import Path
import json
def get_stored_username(path):
"""Get stored username if available."""
if path.exists():
contents = path.read_text()
username = json.loads(contents)
return username
else:
return None
def get_new_username(path):
"""Prompt for a new username."""
username = input("What is your name? ")
contents = json.dumps(username)
path.write_text(contents)
return username
def greet_user():
"""Greet the user by name."""
path = Path('username.json')
username = get_stored_username(path)
if username:
print(f"Welcome back, {username}!")
else:
username = get_new_username(path)
print(f"We'll remember you when you come back, {username}!")
greet_user()
Mỗi hàm trong phiên bản cuối cùng của remember_me.py
có một mục đích rõ ràng. Chúng ta gọi greet_user()
, và hàm đó in ra một thông báo phù hợp: nó hoặc chào đón một người dùng hiện có hoặc chào đón một người dùng mới. Nó làm điều này bằng cách gọi get_stored_username()
, hàm này chỉ chịu trách nhiệm khôi phục một tên người dùng đã lưu trữ nếu có. Cuối cùng, nếu cần thiết, greet_user()
gọi get_new_username()
, hàm này chỉ chịu trách nhiệm lấy một tên người dùng mới và lưu trữ nó. Sự phân chia công việc này là một phần thiết yếu của việc viết mã rõ ràng sẽ dễ bảo trì và mở rộng.
Comments