python / cpython

The Python programming language
https://www.python.org
Other
63.12k stars 30.22k forks source link

Instance of Protocol class can be created if an initialiser is declared. #111660

Open chrisimcevoy opened 11 months ago

chrisimcevoy commented 11 months ago

Bug report

Bug description:

Originally reported on the mypy issue tracker.

I think I have stumbled upon an undocumented change to typing.Protocol between Python 3.10 and 3.11. I am not sure if this change is intentional.

Specifically, as of 3.11 an instance of a Protocol can be created if an initialiser is declared. In previous versions, this would raise TypeError.

from typing import Protocol

class Spam(Protocol):

    def __init__(self):
        print("No TypeError here!")

# In Python 3.9 and 3.10, this raises TypeError
# In Python 3.11 and 3.12, no TypeError is raised.
s = Spam()

CPython versions tested on:

3.9, 3.10, 3.11, 3.12

Operating systems tested on:

Linux

JelleZijlstra commented 11 months ago

This is because we made a change in 3.11 to not clobber the Protocol's __init__ method if it already exists. But that clobbering is how we prevent Protocols from being instantiated, so now you can instantiate the protocol.

If there's a way to fix this without too much impact, I'd accept it, but if not, I think we can safely close this as a won't fix: if the user does something unusual, they shouldn't be surprised if it has unusual effects.