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

Aperta
#157,747 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
1/5
Tempo stimato
1-3 ore
Idoneità per principianti
30/100
Tipo di issue
Documentazione
Chiarezza
Specificata chiaramente
Stato di attività
Ferma
Stack tecnologico
python
Ambito
documentation

Direzione di ricerca

Esamina la PR collegata gh-157771 insieme alla documentazione sulle visualizzazioni di Dictionary e sul mapping citata nell’issue. Verifica la formulazione rispetto al comportamento a runtime descritto di keys() e getitem; il lavoro è completato quando la documentazione non richiede più l’ereditarietà da Mapping e rimane coerente con la costruzione di dict.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

docs

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
Lingua principale
Python
Stelle
77.2k
Fork
36k
Merge medio
1g 9h
PR unite (30g)
558

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di python/cpython

Tutte le issue di python/cpython

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.