DEV Community

Super Kai (Kazuya Ito)
Super Kai (Kazuya Ito)

Posted on

Type hints in Python (6)

Buy Me a Coffee

*Memo:

Callable and Protocol can be used for a function as shown below:

*Memo:

  • Callable can specify function parameter and return types, doing less than Protocol:
    • The 1st argument is paramtypes(Required:-Type:list(Type) or ellipsis):
      • It's a list of one or more parameter types.
      • ... (but not Ellipsis) can be used to accept the zero or more arguments of all types but it shouldn't be used because it's too gereral:
        • ... is different from Any which accepts the one argument of all types.
      • Don't use paramtypes=.
    • The 2nd argument is returntype(Required-Type:Type)):
      • It's a return type.
      • Don't use returntype=.
  • Protocol can specify a function signature, doing more than Callable:
    • It has no arguments.
    • It can be used by extended.
    • The method with the signature which you want to specify should be defined in the extended class:
    • Specific parameter default values and body aren't necessary because they affect nothing but they can still be set if you want.
      • ... shows the presence of default values and body but specific ones aren't there:
      • Even if specific parameter default values can be set, their types must be suitable.
    • The static method without self can also be used.
  • For *args with Callable, the specific type [*tuple[type, ...]] can be used but for **kwargs with Callable, there is no specific type so only the general type ... can be used, accepting the zero or more arguments of all types, which isn't good so for **kwargs, Protocol should be used.

<With normal parameters>:

from collections.abc import Callable
from typing import Protocol

def func(x: int, y: int | float = 4) -> str:
    return f'x+y={x+y}'

print(func(5))        # No error
print(func(x=5))      # No error
print(func(5, 2))     # No error
print(func(x=5, y=2)) # No error

v1: Callable[[int, int | float], str] = func
# v1: Callable[..., str] = func

print(v1(5))        # Error
print(v1(x=5))      # Error
print(v1(5, 2))     # No error
print(v1(x=5, y=2)) # Error

class MyType(Protocol):
    def __call__(self, x: int, y: int | float = ...) -> str: ...
    # @staticmethod
    # def __call__(x: int, y: int | float = ...) -> str: ...

v2: MyType = func

print(v2(5))        # No error
print(v2(x=5))      # No error
print(v2(5, 2))     # No error
print(v2(x=5, y=2)) # No error
Enter fullscreen mode Exit fullscreen mode

<With *args>:

from collections.abc import Callable
from typing import Protocol

def func(*args: int) -> str:
    return f'{args}'

print(func(0, 1, 2)) # No error

v1: Callable[[*tuple[int, ...]], str] = func
# v1: Callable[..., str] = func

print(v1(0, 1, 2)) # No error

class MyType(Protocol):
    def __call__(self, *args: int) -> str: ...
    # @staticmethod
    # def __call__(*args: int) -> str: ...

v2: MyType = func

print(v2(0, 1, 2)) # No error
Enter fullscreen mode Exit fullscreen mode

<With **kwargs>:

from collections.abc import Callable
from typing import Protocol

def func(**kwargs: float) -> str:
    return f'{kwargs}'

print(func(x=0.0, y=1.0, z=2.0)) # No error

v1: Callable[..., str] = func

print(v1(x=0.0, y=1.0, z=2.0)) # No error

class MyType(Protocol):
    def __call__(self, **kwargs: float) -> str: ...
    # @staticmethod
    # def __call__(**kwargs: float) -> str: ...

v2: MyType = func

print(v2(x=0.0, y=1.0, z=2.0)) # No error
Enter fullscreen mode Exit fullscreen mode

<With *args & **kwargs>:

from collections.abc import Callable
from typing import Protocol

def func(*args: int, **kwargs: float) -> str:
    return f'{args} {kwargs}'

print(func(0, 1, 2))                      # No error
print(func(x=0.0, y=1.0, z=2.0))          # No error
print(func(0, 1, 2, x=0.0, y=1.0, z=2.0)) # No error

v1: Callable[..., str] = func

print(v1(0, 1, 2))                      # No error
print(v1(x=0.0, y=1.0, z=2.0))          # No error
print(v1(0, 1, 2, x=0.0, y=1.0, z=2.0)) # No error

class MyType(Protocol):
    def __call__(self, *args: int, **kwargs: float) -> str: ...
    # @staticmethod
    # def __call__(*args: int, **kwargs: float) -> str: ...

v2: MyType = func

print(v2(0, 1, 2))                      # No error
print(v2(x=0.0, y=1.0, z=2.0))          # No error
print(v2(0, 1, 2, x=0.0, y=1.0, z=2.0)) # No error
Enter fullscreen mode Exit fullscreen mode

Top comments (0)