Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Subclassing Protocol get different __init__ #644

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
superChing opened this issue Jun 11, 2019 · 2 comments
Closed

Subclassing Protocol get different __init__ #644

superChing opened this issue Jun 11, 2019 · 2 comments

Comments

@superChing
Copy link

superChing commented Jun 11, 2019

When we subclassing Protocol, we get a __init__ differing from default one but the protocol in question didn't define any __init__.

example

Previously, pure class __init__ take no arguments.

In [21]: class B:
    ...:     pass

In [22]: B(b=1,c=2)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-22-9790dbc81f4f> in <module>
----> 1 B(b=1,c=2)

TypeError: B() takes no arguments

Now with Protocol, we get different __init__ API implicitly.

In [20]: from typing_extensions import Protocol
    ...: from typing import *
    ...:
    ...: class A(Protocol):
    ...:     a:int
    ...:
    ...: class B(A):
    ...:     pass
    ...:
    ...: B(b=1,c=2)
Out[20]: <__main__.B at 0x10a866198>

It seems that it inherit __init__(self,*args,**kwargs) from Protocol.

But the document (mypy) does not say anything about it.
This is not intuitive and surprising. At least any sane programmer would assume that __init__ didn't change, in reasoning that Protocol is just pure interface thus nothing would be inherited.


ENV

➜ pip show typing_extensions
Name: typing-extensions
Version: 3.7.2
Summary: Backported and Experimental Type Hints for Python 3.5+
Home-page: https://github.com/python/typing/blob/master/typing_extensions/README.rst
Author: Guido van Rossum, Jukka Lehtosalo, Lukasz Langa, Michael Lee
Author-email: [email protected]
License: PSF
Location: /Users/catch22/miniconda3/lib/python3.7/site-packages
Requires:
Required-by:

➜ ipython
Python 3.7.1 (default, Dec 14 2018, 13:28:58)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.2.0 -- An enhanced Interactive Python. Type '?' for help.

@uriyyo
Copy link
Member

uriyyo commented Aug 2, 2021

This issue is fixed by python/cpython#27545

@RamiAwar
Copy link

Still getting this in Python 3.12 I believe. When I define an empty init in the class inheriting from the protocol my issues are solved. And they are only caused if I inherit from a Protocol.

Maybe it's linked to the fact that I'm using a generic Protocol but I wouldn't know much about this.

...

# Generic types per repository
Model = TypeVar("Model", bound=DbBaseModel)
TCreate = TypeVar("TCreate", bound=BaseModel, contravariant=True)
TUpdate = TypeVar("TUpdate", bound=BaseModel, contravariant=True)

# Only used as input
ModelSchema = TypeVar("ModelSchema", bound=BaseModel)
Data = TypeVar("Data", bound=BaseModel)


class RepositoryProtocol(Protocol[Model, TCreate, TUpdate]):
    @property
    def model(self) -> Type[Model]: ...
class BaseRepository(ABC, RepositoryProtocol[Model, TCreate, TUpdate]):

    @property
    @abstractmethod
    def model(self) -> Type[Model]:
        raise NotImplementedError

I noticed this as I was using BaseRepository as a dependency in a FastAPI route. As soon as I added the protocol, the route was expecting *args, *kwargs as required arguments.

As soon as I remove the protocol, this is fixed again.
When I kept the Protocol but defined an empty init in BaseRepository, it was also fixed.

    def __init__(self) -> None: ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants