python / python/cpython

[docs] dictionary unpacking `fn(**kwargs)` should accept `SupportsKeysAndGetitem` and not just `Mapping`

Đang mở
#157,747 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

docs
Ngôn ngữ chính
Python
Star
77.2k
Fork
35.9k
Chỉ số merge pull request
Chỉ số pull request đang chờ

Mô tả

Brief

The docs say that for dict unpacking as in fn(**kwargs), kwargs must "implement the methods specified in the collections.abc.Mapping", when in reality only keys() and __getitem__ as in the dict constructor are required.

Documentation

The current documentation states that:

[6.2.5.4. Dictionary displays]
Instead of a key-value pair, a dict item may be an expression prefixed by a double asterisk **. This denotes dictionary unpacking. At runtime, the expression must evaluate to a mapping;

which points to

[mapping]
A container object that supports arbitrary key lookups and implements the methods specified in the collections.abc.Mapping or collections.abc.MutableMapping abstract base classes.

However, at runtime, fn(**kwargs) works whenever kwargs supports both a keys() -> Iterable[str] and __getitem__(self, key: str) -> object method:

class SupportsKeysAndGetitem:
    _dict = {"foo": 0, "bar": object()}

    def keys(self):
        return iter(self._dict)

    def __getitem__(self, key: str, /) -> object:
        return self._dict[key]

def expects_kwargs(**kwargs: int) -> None:
    print(kwargs)

d = SupportsKeysAndGetitem()
expects_kwargs(**d)  # works at runtime

Moreover, the relevant methods that Cpython executes under the hood explicitly supports this looser protocol:

class dict
If a positional argument is given and it defines a keys() method, a dictionary is created by calling getitem() on the argument with each returned key from the method.

and

int PyDict_Merge(PyObject *a, PyObject *b, int override)
Part of the Stable ABI. Thread safety: Safe for concurrent use on the same object.
Iterate over mapping object b adding key-value pairs to dictionary a. b may be a dictionary, or any object supporting PyMapping_Keys() and PyObject_GetItem().

Proposal

Update the documentation of dict-unpacking to reflect the actual runtime behavior in sync with how dict construction works, only requiring keys() and __getitem__ rather than inheritance from the non-protocol class collections.abc.Mapping.

Rationale

  • fn(**kwargs) only requiring keys() and __getitem__ is how it works at runtime, and has since ages
  • Supporting a protocol is nicer than just supporting a non-protocol ABC like collections.abc.Mapping due to duck-typing (a similar conclusion was reached in the discussion of #116938)
  • There are real world use-cases like fn(**dataframe) as for example a pandas DataFrame supports keys() (yields the list of columns) and __getitem__ (look up column by name), but does not inherit from the collections.abc.Mapping class, nor implements all of its methods.
Linked PRs
  • gh-157771

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Xem xét PR được liên kết gh-157771 cùng với tài liệu về hiển thị Dictionary và mapping được trích dẫn trong issue. Kiểm tra cách diễn đạt dựa trên hành vi lúc chạy được mô tả của keys() và getitem; được coi là hoàn tất khi tài liệu không còn yêu cầu kế thừa Mapping và vẫn nhất quán với việc xây dựng dict.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
python
Lĩnh vực
documentation
Loại issue
Tài liệu
Độ khó
1/5
Thời gian dự kiến
1-3 giờ
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
30/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.