python / python/mypy

Why is `Callable` assumed to be a user defined function?

Offen
#14,392 10 Kommentare 7 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Vorherrschende Sprache
Python
Sterne
20.6k
Forks
3.3k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

The following should be an error, but it currently is not.

from collections.abc import Callable
from typing import Any


def f(call: Callable[..., Any]) -> None:
    print(call.__name__)  # why is there no error here?

IMO the last line should cause a mypy error to the effect of "Callable" has no attribute "__name__". The callable protocol generally does not define __name__.

To further drive this point home, add the following piece:

class Bar:
    def __call__(self) -> None:
        print(f"hi mom")


f(Bar())  # this is valid
print(Bar().__name__)  # this is an error

This means that

  1. Bar is correctly viewed as being a Callable subtype (structurally) and
  2. it is also correctly identified to not have the __name__ attribute by mypy.
  3. Yet when something is annotated as Callable, mypy just assumes it has the __name__ attribute. 🤨

Correct me if I am wrong, but these points cannot logically all be true.


The documentation of the Callable ABC clearly states that it is a class that defines the __call__ method. Nowhere does it mention the need for a Callable class to define __name__ (or anything else for that matter).

There is also no mention of any attributes/methods other than __call__ in the glossary entry for callable.

Lastly, the relevant section on Callable types of the standard type hierarchy chapter in the data model documentation again broadly defines them as

types to which the function call operation [...] can be applied

and further down even explicitly states the following:

Instances of arbitrary classes can be made callable by defining a __call__() method in their class.


I realize that user defined functions do always have the __name__ attribute (as well as a bunch of others listed in the aforementioned data model docs). But this should make them a subtype of Callable.

Yet it seems as though mypy treats a Callable as a user defined function. My example f above can be changed to any of the attributes of user defined functions, such as __kwdefaults__ for example and it would still pass mypy checks. This seems wildly inconsistent with all the documentation I could find, as well as logically inconsistent in itself.

I can only assume that there is some historic/pragmatic explanation for this, but I could not find it.

What is the reasoning behind this?


I found a discussion in #5958 that seems to be related, but found no answer to my question.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne mit den Beispielen im Issue und vergleiche mypy's Behandlung von collections.abc.Callable mit dem Verhalten von Bar und benutzerdefinierten Funktionen. Lies die zugehörige Diskussion in issue #5958 und prüfe die ungeklärte Frage, ob Callable Funktionsattribute offenlegen sollte. Erledigt wäre dies, wenn ein vereinbartes Verhalten sowie eine entsprechende Dokumentation oder Tests vorliegen.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
devtools
Issue-Typ
Bug
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Veraltet
Klarheit
Muss geklärt werden
Anfängerfreundlichkeit
25/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.