DEV Community

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

Posted on

Type hints in Python (7)

Buy Me a Coffee

*Memo:

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

*Memo:

  • Callable can specify argument and return types, doing less than Protocol:
    • The 1st argument is argtypes(Required:-Type:list(Type) or ellipsis):
      • It's a list of one or more argument types.
      • Use the empty list '[]' for no arguments.
      • ... (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 argtypes=.
    • 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 & str return value>:

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 no parameters & None return value>:

from collections.abc import Callable
from typing import Protocol

def func() -> None:
    print('Hello')

func() # No error

v1: Callable[[], None] = func
# v1: Callable[..., None] = func

v1() # No error

class MyType(Protocol):
    def __call__(self) -> None: ...
    # @staticmethod
    # def __call__() -> None: ...

v2: MyType = func

v2() # No error
Enter fullscreen mode Exit fullscreen mode

<With *args & str return value>:

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 & str return value>:

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 & str return value>:

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)