Dễ dàng trích xuất giá trị nếu chúng ta có chìa khóa, giống như mở ổ khóa bằng chìa khóa. Tuy nhiên, điều ngược lại không hề đơn giản, kiểu như “bẻ chìa có ổ”, có thể
Đôi khi, việc trích xuất khóa trở nên quan trọng, đặc biệt khi khóa và giá trị có mối quan hệ một đối một. Đó là, khi một trong số chúng là duy nhất và do đó có thể đóng vai trò là khóa
Một ngày nọ, tôi đã hỏi trên LinkedIn rằng liệu mọi người có hào hứng với việc khớp mẫu trong Python 3 không. 10
Một phần ba số người được hỏi không biết khớp mẫu là gì, vì vậy thật là một dịp hoàn hảo để viết một bài đăng trên blog về nó
Như với tất cả các cấu trúc, khớp mẫu không cần thiết cho các ngôn ngữ lập trình. Python đạt phiên bản 3. 10 trước khi nhận được nó. Nhưng đó là một tính năng cho phép chúng tôi viết mã rõ ràng hơn và thường chính xác hơn
Và nếu bạn thích các ngôn ngữ lập trình chức năng — chẳng hạn như Erlang, Haskell, v.v. — thì có thể bạn đã bỏ qua khớp mẫu khi viết Python
Tôi đã làm, vì vậy tôi rất vui vì tính năng này sẽ có sẵn trong Python 3. 10 [hiện đang ở phiên bản beta 4]
Trong Python, khớp mẫu sẽ hoạt động như thế này
match statement:
case condition_1:
do_something[]
case condition_2:
do_something_else[]
case _:
do_something_else_as_nothing_matched[]
Python sẽ kiểm tra xem
match [3, 5]:
case [a, ]:
print[a] # this does **not** match as [a, ] is a single element tuple
# while [3, 5] is a two elements tuple
case [a, b]:
print[b ** 2] # this will print 25 as [a, b] is a two element tubple
# just like [3, 5]
3 có khớp với match [3, 5]:
case [a, ]:
print[a] # this does **not** match as [a, ] is a single element tuple
# while [3, 5] is a two elements tuple
case [a, b]:
print[b ** 2] # this will print 25 as [a, b] is a two element tubple
# just like [3, 5]
4 không, sau đó là match [3, 5]:
case [a, ]:
print[a] # this does **not** match as [a, ] is a single element tuple
# while [3, 5] is a two elements tuple
case [a, b]:
print[b ** 2] # this will print 25 as [a, b] is a two element tubple
# just like [3, 5]
5 và nếu không có gì khớp, nó sẽ khớp với match [3, 5]:
case [a, ]:
print[a] # this does **not** match as [a, ] is a single element tuple
# while [3, 5] is a two elements tuple
case [a, b]:
print[b ** 2] # this will print 25 as [a, b] is a two element tubple
# just like [3, 5]
6 [một kiểu bắt tất cả]match [3, 5]:
case [a, ]:
print[a] # this does **not** match as [a, ] is a single element tuple
# while [3, 5] is a two elements tuple
case [a, b]:
print[b ** 2] # this will print 25 as [a, b] is a two element tubple
# just like [3, 5]
7 có thể khá thông minh, ví dụ: giả sử match [3, 5]:
case [a, ]:
print[a] # this does **not** match as [a, ] is a single element tuple
# while [3, 5] is a two elements tuple
case [a, b]:
print[b ** 2] # this will print 25 as [a, b] is a two element tubple
# just like [3, 5]
3 là match [3, 5]:
case [a, ]:
print[a] # this does **not** match as [a, ] is a single element tuple
# while [3, 5] is a two elements tuple
case [a, b]:
print[b ** 2] # this will print 25 as [a, b] is a two element tubple
# just like [3, 5]
9 và match [3, 5]:
case [a, ]:
print[a] # this does **not** match as [a, ] is a single element tuple
# while [3, 5] is a two elements tuple
case [a, b]:
print[b ** 2] # this will print 25 as [a, b] is a two element tubple
# just like [3, 5]
4 là from typing import Any, Dict, Iterable, Hashable, Optional
def extract_fields_from_records[
records: Iterable[Dict],
fields: set[Hashable],
missing: str,
_default: Dict[Hashable, Hashable]=dict[]
] -> Iterable[Dict]:
"""
Returns a generator of dictionaries whose keys are present in `fields`,
starting from an iterable of dictionaries.
:param records: A iterable of dictionaries
:param fields: Fields to include
:param missing: How to handle missing fields. If `omit`, missing fields are
simply omitted. If `fill`, missing fields are added with the default value
`_default`. If `raise`, a KeyError is raised if any values are missing.
:param _default: When `missing="fill"` look up by key for the value to
fill.
"""
if missing == "omit":
_records = [
{k: v for k, v in rec.items[] if k in fields} for rec in records
]
elif missing == "fill":
_records = [
{k: rec.get[k, _default.get[k, None]] for k in fields}
for rec in records
]
elif missing == "raise":
_records = [{k: rec[k] for k in fields} for rec in records]
else:
raise ValueError[
"Unknown value for `missing`. Valid values are"
" 'omit', 'fill' and 'raise'."
]
return _records
1. Chúng ta có thể viết một cái gì đó nhưmatch [3, 5]:
case [a, ]:
print[a] # this does **not** match as [a, ] is a single element tuple
# while [3, 5] is a two elements tuple
case [a, b]:
print[b ** 2] # this will print 25 as [a, b] is a two element tubple
# just like [3, 5]
Bạn có thể thấy điều này mạnh mẽ như thế nào
Để xem nó hoạt động như thế nào, tôi đã tìm một số mã có chứa một vài câu lệnh
from typing import Any, Dict, Iterable, Hashable, Optional
def extract_fields_from_records[
records: Iterable[Dict],
fields: set[Hashable],
missing: str,
_default: Dict[Hashable, Hashable]=dict[]
] -> Iterable[Dict]:
"""
Returns a generator of dictionaries whose keys are present in `fields`,
starting from an iterable of dictionaries.
:param records: A iterable of dictionaries
:param fields: Fields to include
:param missing: How to handle missing fields. If `omit`, missing fields are
simply omitted. If `fill`, missing fields are added with the default value
`_default`. If `raise`, a KeyError is raised if any values are missing.
:param _default: When `missing="fill"` look up by key for the value to
fill.
"""
if missing == "omit":
_records = [
{k: v for k, v in rec.items[] if k in fields} for rec in records
]
elif missing == "fill":
_records = [
{k: rec.get[k, _default.get[k, None]] for k in fields}
for rec in records
]
elif missing == "raise":
_records = [{k: rec[k] for k in fields} for rec in records]
else:
raise ValueError[
"Unknown value for `missing`. Valid values are"
" 'omit', 'fill' and 'raise'."
]
return _records
2/from typing import Any, Dict, Iterable, Hashable, Optional
def extract_fields_from_records[
records: Iterable[Dict],
fields: set[Hashable],
missing: str,
_default: Dict[Hashable, Hashable]=dict[]
] -> Iterable[Dict]:
"""
Returns a generator of dictionaries whose keys are present in `fields`,
starting from an iterable of dictionaries.
:param records: A iterable of dictionaries
:param fields: Fields to include
:param missing: How to handle missing fields. If `omit`, missing fields are
simply omitted. If `fill`, missing fields are added with the default value
`_default`. If `raise`, a KeyError is raised if any values are missing.
:param _default: When `missing="fill"` look up by key for the value to
fill.
"""
if missing == "omit":
_records = [
{k: v for k, v in rec.items[] if k in fields} for rec in records
]
elif missing == "fill":
_records = [
{k: rec.get[k, _default.get[k, None]] for k in fields}
for rec in records
]
elif missing == "raise":
_records = [{k: rec[k] for k in fields} for rec in records]
else:
raise ValueError[
"Unknown value for `missing`. Valid values are"
" 'omit', 'fill' and 'raise'."
]
return _records
3/_______9_______4Mã ban đầu lớn hơn một chút và chứa chức năng bổ sung hiện nằm ngoài phạm vi, vì vậy tôi đã tách các bit thú vị
from typing import Any, Dict, Iterable, Hashable, Optional
def extract_fields_from_records[
records: Iterable[Dict],
fields: set[Hashable],
missing: str,
_default: Dict[Hashable, Hashable]=dict[]
] -> Iterable[Dict]:
"""
Returns a generator of dictionaries whose keys are present in `fields`,
starting from an iterable of dictionaries.
:param records: A iterable of dictionaries
:param fields: Fields to include
:param missing: How to handle missing fields. If `omit`, missing fields are
simply omitted. If `fill`, missing fields are added with the default value
`_default`. If `raise`, a KeyError is raised if any values are missing.
:param _default: When `missing="fill"` look up by key for the value to
fill.
"""
if missing == "omit":
_records = [
{k: v for k, v in rec.items[] if k in fields} for rec in records
]
elif missing == "fill":
_records = [
{k: rec.get[k, _default.get[k, None]] for k in fields}
for rec in records
]
elif missing == "raise":
_records = [{k: rec[k] for k in fields} for rec in records]
else:
raise ValueError[
"Unknown value for `missing`. Valid values are"
" 'omit', 'fill' and 'raise'."
]
return _records
Cách sử dụng rất đơn giản
records = [
{"age": 25, "height": 1.9},
{"age": 45, "height": 1.6, "country": "NL"},
]
list[
extract_fields_from_records[
records,
{"age", "country"},
missing="fill",
_default={"country": "World"}
]
]
dẫn đến
[
{'country': 'World', 'age': 25},
{'country': 'NL', 'age': 45}
]
Vậy chức năng này sẽ trông như thế nào với khớp mẫu?
def _extract_fields_from_records[
records: Iterable[Dict],
fields: set[Hashable],
missing: str,
_default: Dict[Hashable, Hashable]=dict[]
] -> Iterable[Dict]:
match missing:
case "omit":
fields = set[fields]
_records = [
{k: v for k, v in rec.items[] if k in fields}
for rec in records
]
case "fill":
_records = [
{k: rec.get[k, _default.get[k, None]] for k in fields}
for rec in records
]
case "raise":
_records = [{k: rec[k] for k in fields} for rec in records]
case _:
raise ValueError[
"Unknown value for `missing`. Valid values are"
" 'omit', 'fill' and 'raise'."
]
return _records
Mặc dù vậy, ví dụ này rất đơn giản vì nó rất "tuyến tính" và tất cả những gì tôi đang làm là tiết kiệm cho mình một số thao tác gõ bằng cách tránh
from typing import Any, Dict, Iterable, Hashable, Optional
def extract_fields_from_records[
records: Iterable[Dict],
fields: set[Hashable],
missing: str,
_default: Dict[Hashable, Hashable]=dict[]
] -> Iterable[Dict]:
"""
Returns a generator of dictionaries whose keys are present in `fields`,
starting from an iterable of dictionaries.
:param records: A iterable of dictionaries
:param fields: Fields to include
:param missing: How to handle missing fields. If `omit`, missing fields are
simply omitted. If `fill`, missing fields are added with the default value
`_default`. If `raise`, a KeyError is raised if any values are missing.
:param _default: When `missing="fill"` look up by key for the value to
fill.
"""
if missing == "omit":
_records = [
{k: v for k, v in rec.items[] if k in fields} for rec in records
]
elif missing == "fill":
_records = [
{k: rec.get[k, _default.get[k, None]] for k in fields}
for rec in records
]
elif missing == "raise":
_records = [{k: rec[k] for k in fields} for rec in records]
else:
raise ValueError[
"Unknown value for `missing`. Valid values are"
" 'omit', 'fill' and 'raise'."
]
return _records
5 mỗi lần. Thật dễ dàng để thể hiện với from typing import Any, Dict, Iterable, Hashable, Optional
def extract_fields_from_records[
records: Iterable[Dict],
fields: set[Hashable],
missing: str,
_default: Dict[Hashable, Hashable]=dict[]
] -> Iterable[Dict]:
"""
Returns a generator of dictionaries whose keys are present in `fields`,
starting from an iterable of dictionaries.
:param records: A iterable of dictionaries
:param fields: Fields to include
:param missing: How to handle missing fields. If `omit`, missing fields are
simply omitted. If `fill`, missing fields are added with the default value
`_default`. If `raise`, a KeyError is raised if any values are missing.
:param _default: When `missing="fill"` look up by key for the value to
fill.
"""
if missing == "omit":
_records = [
{k: v for k, v in rec.items[] if k in fields} for rec in records
]
elif missing == "fill":
_records = [
{k: rec.get[k, _default.get[k, None]] for k in fields}
for rec in records
]
elif missing == "raise":
_records = [{k: rec[k] for k in fields} for rec in records]
else:
raise ValueError[
"Unknown value for `missing`. Valid values are"
" 'omit', 'fill' and 'raise'."
]
return _records
6Tuy nhiên, khớp mẫu trở nên mạnh mẽ khi chúng tôi yêu cầu Python phân tách mẫu mà chúng tôi muốn khớp
Giả sử chúng ta đang lấy dữ liệu từ đâu đó và chúng ta cần định hình dữ liệu đó đúng cách [Điều đó xảy ra thường xuyên như thế nào, phải không?. ]
Dữ liệu đến có thể có dạng sau
{
"generic_key": [1, 2, 3],
# other stuff
}
hoặc là
{
"generic_key": 1, # integer and not a list
# other stuff
}
hoặc là
{
"log_me": "message",
}
Trong trường hợp cuối cùng này, chúng ta không nên xử lý dữ liệu và chỉ ghi nhật ký
from typing import Any, Dict, Iterable, Hashable, Optional
def extract_fields_from_records[
records: Iterable[Dict],
fields: set[Hashable],
missing: str,
_default: Dict[Hashable, Hashable]=dict[]
] -> Iterable[Dict]:
"""
Returns a generator of dictionaries whose keys are present in `fields`,
starting from an iterable of dictionaries.
:param records: A iterable of dictionaries
:param fields: Fields to include
:param missing: How to handle missing fields. If `omit`, missing fields are
simply omitted. If `fill`, missing fields are added with the default value
`_default`. If `raise`, a KeyError is raised if any values are missing.
:param _default: When `missing="fill"` look up by key for the value to
fill.
"""
if missing == "omit":
_records = [
{k: v for k, v in rec.items[] if k in fields} for rec in records
]
elif missing == "fill":
_records = [
{k: rec.get[k, _default.get[k, None]] for k in fields}
for rec in records
]
elif missing == "raise":
_records = [{k: rec[k] for k in fields} for rec in records]
else:
raise ValueError[
"Unknown value for `missing`. Valid values are"
" 'omit', 'fill' and 'raise'."
]
return _records
7Thay vào đó, trong hai trường hợp đầu tiên, chúng ta cần làm gì đó với các phần tử của danh sách hoặc một số nguyên. Và đầu ra phải luôn là một danh sách, bởi vì chúng tôi không muốn người tiêu dùng chức năng của chúng tôi viết thêm logic để xử lý việc phân tách danh sách/số nguyên. Làm cách nào để viết một hàm như vậy mà không khớp mẫu?
from typing import Optional
def transform_dictionary[dct: dict] -> Optional[list[int]]:
message = dct.get["log_me"]
values = dct.get["generic_key", []]
if message:
print[message] # this should be a log statement!!
elif isinstance[values, list]:
return [value ** 2 for value in values] # this is our transformation, insert your own
elif isinstance[values, int]:
return [values ** 2]
else:
ValueError[f"Input %{dct} is not of the required shape"]
transform_dictionary[{"log_me": "error"}]
print[transform_dictionary[{"generic_key": [1, 2, 3]}]]
print[transform_dictionary[{"generic_key": 1}]]
match [3, 5]:
case [a, ]:
print[a] # this does **not** match as [a, ] is a single element tuple
# while [3, 5] is a two elements tuple
case [a, b]:
print[b ** 2] # this will print 25 as [a, b] is a two element tubple
# just like [3, 5]
0Cách trên hoạt động tốt và đó là cách bạn có thể viết Python ngày nay, nhưng bạn có nhận thấy chi phí tinh thần khi cố gắng hiểu cấu trúc dữ liệu mà bạn đang nhận được không? . Khớp mẫu giúp dễ hiểu hơn
match [3, 5]:
case [a, ]:
print[a] # this does **not** match as [a, ] is a single element tuple
# while [3, 5] is a two elements tuple
case [a, b]:
print[b ** 2] # this will print 25 as [a, b] is a two element tubple
# just like [3, 5]
1match [3, 5]:
case [a, ]:
print[a] # this does **not** match as [a, ] is a single element tuple
# while [3, 5] is a two elements tuple
case [a, b]:
print[b ** 2] # this will print 25 as [a, b] is a two element tubple
# just like [3, 5]
0Bây giờ, chỉ bằng cách đọc mã, tôi hiểu các định dạng mà
from typing import Any, Dict, Iterable, Hashable, Optional
def extract_fields_from_records[
records: Iterable[Dict],
fields: set[Hashable],
missing: str,
_default: Dict[Hashable, Hashable]=dict[]
] -> Iterable[Dict]:
"""
Returns a generator of dictionaries whose keys are present in `fields`,
starting from an iterable of dictionaries.
:param records: A iterable of dictionaries
:param fields: Fields to include
:param missing: How to handle missing fields. If `omit`, missing fields are
simply omitted. If `fill`, missing fields are added with the default value
`_default`. If `raise`, a KeyError is raised if any values are missing.
:param _default: When `missing="fill"` look up by key for the value to
fill.
"""
if missing == "omit":
_records = [
{k: v for k, v in rec.items[] if k in fields} for rec in records
]
elif missing == "fill":
_records = [
{k: rec.get[k, _default.get[k, None]] for k in fields}
for rec in records
]
elif missing == "raise":
_records = [{k: rec[k] for k in fields} for rec in records]
else:
raise ValueError[
"Unknown value for `missing`. Valid values are"
" 'omit', 'fill' and 'raise'."
]
return _records
8 có thể có, không cần tài liệu. Chúng tôi cũng thấy một số tính năng mạnh mẽ mà chúng tôi chưa từng thấy trước đây. Bằng cách viết from typing import Any, Dict, Iterable, Hashable, Optional
def extract_fields_from_records[
records: Iterable[Dict],
fields: set[Hashable],
missing: str,
_default: Dict[Hashable, Hashable]=dict[]
] -> Iterable[Dict]:
"""
Returns a generator of dictionaries whose keys are present in `fields`,
starting from an iterable of dictionaries.
:param records: A iterable of dictionaries
:param fields: Fields to include
:param missing: How to handle missing fields. If `omit`, missing fields are
simply omitted. If `fill`, missing fields are added with the default value
`_default`. If `raise`, a KeyError is raised if any values are missing.
:param _default: When `missing="fill"` look up by key for the value to
fill.
"""
if missing == "omit":
_records = [
{k: v for k, v in rec.items[] if k in fields} for rec in records
]
elif missing == "fill":
_records = [
{k: rec.get[k, _default.get[k, None]] for k in fields}
for rec in records
]
elif missing == "raise":
_records = [{k: rec[k] for k in fields} for rec in records]
else:
raise ValueError[
"Unknown value for `missing`. Valid values are"
" 'omit', 'fill' and 'raise'."
]
return _records
9 và records = [
{"age": 25, "height": 1.9},
{"age": 45, "height": 1.6, "country": "NL"},
]
list[
extract_fields_from_records[
records,
{"age", "country"},
missing="fill",
_default={"country": "World"}
]
]
0, Python liên kết — tương ứng — records = [
{"age": 25, "height": 1.9},
{"age": 45, "height": 1.6, "country": "NL"},
]
list[
extract_fields_from_records[
records,
{"age", "country"},
missing="fill",
_default={"country": "World"}
]
]
1 đến records = [
{"age": 25, "height": 1.9},
{"age": 45, "height": 1.6, "country": "NL"},
]
list[
extract_fields_from_records[
records,
{"age", "country"},
missing="fill",
_default={"country": "World"}
]
]
2 và records = [
{"age": 25, "height": 1.9},
{"age": 45, "height": 1.6, "country": "NL"},
]
list[
extract_fields_from_records[
records,
{"age", "country"},
missing="fill",
_default={"country": "World"}
]
]
3 đến records = [
{"age": 25, "height": 1.9},
{"age": 45, "height": 1.6, "country": "NL"},
]
list[
extract_fields_from_records[
records,
{"age", "country"},
missing="fill",
_default={"country": "World"}
]
]
4Tất nhiên là còn nhiều thứ nữa [ví dụ như bảo vệ]. trong trường hợp bạn tò mò, PEP 634 cung cấp thông số kỹ thuật đầy đủ và PEP 636 trình bày hướng dẫn