Các khóa khớp trong từ điển Python

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_______4

Mã 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
6

Tuy 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
7

Thay 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]
0

Cá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]
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]
0

Bâ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"}
    ]
]
4

Tấ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

Làm cách nào để kiểm tra xem khóa từ điển có khớp với Python không?

Kiểm tra xem khóa có tồn tại hay không bằng cách sử dụng phương thức get[] . Nếu không có khóa, nó sẽ trả về một giá trị mặc định [nếu được thông qua] hoặc nó trả về Không có. Sử dụng phương pháp này, chúng ta có thể chuyển một khóa và kiểm tra xem khóa có tồn tại trong từ điển python không.

Từ điển Python có thể có 2 khóa giống nhau không?

Đầu tiên, một khóa nhất định chỉ có thể xuất hiện trong từ điển một lần. Không cho phép sao chép khóa . Từ điển ánh xạ mỗi khóa thành một giá trị tương ứng, vì vậy sẽ không hợp lý khi ánh xạ một khóa cụ thể nhiều lần.

Bạn có thể sử dụng == trên từ điển trong Python không?

Theo tài liệu python, bạn thực sự có thể sử dụng toán tử == trên từ điển .

Từ điển có thể có hai khóa giống nhau với các giá trị khác nhau không?

Bạn không thể . Các khóa phải là duy nhất.

Chủ Đề