DEV Community

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

Posted on • Edited on

Type hints in Python (2)

Buy Me a Coffee

*Memo:

Running python test.py, error doesn't occur with a wrong type hint as shown below:

v: int | list[float] = 'Hello'
# No error

print(v)
# Hello
Enter fullscreen mode Exit fullscreen mode

complex accepts float, int and bool, float accepts int and bool and int accepts bool as shown below:

*Memo:

  • These types behave like having the relationship of a supertype and subtype even though they actually don't have such a relationship except int and bool:
    • bool is a subtype of int according to the doc.
    • I call the type which isn't a supertype but accepts other types a supertype-like type so for example, complex is a supertype-like type of float, int and bool.
    • I call the type which isn't a subtype but is accepted by other types a subtype-like type so for example, bool is a subtype-like type of complex and float.
  • PEP 484 explains the numeric tower of complex, float and int.

<complex>:

v: complex = 2.3+4.5j # complex
v = 2.3               # float
v = 23                # int
v = True              # bool
# No error
Enter fullscreen mode Exit fullscreen mode

<float>:

v: float = 2.3 # float
v = 23         # int
v = True       # bool
# No error

v = 2.3+4.5j   # complex
# Error
Enter fullscreen mode Exit fullscreen mode

<int>:

v: int = 23  # int
v = True     # bool
# No error

v = 2.3+4.5j # complex
v = 2.3      # float
# Error
Enter fullscreen mode Exit fullscreen mode

<bool>:

v: bool = True # bool
# No error

v = 2.3+4.5j   # complex
v = 2.3        # float
v = 23         # int
# Error
Enter fullscreen mode Exit fullscreen mode

Any and object can be used to accept all types as shown below:

*Memo:

  • Any can accept and behave like all types because Any is the special type to indicate an unconstrained type:
    • Type checkers ignore Any so it's equivalent to no type hint.
    • We can say that Any is a supertype-like type of all other types.
  • object can accept all types but cannot behave like all types except object because object is one specific type which is a supertype of all other types:
    • Type checkers check object as one specific type.
  • Use Any and object if using more specific type is impossible:
    • Use object prior to Any because object is more specific.

<Any>:

from typing import Any

v: Any = 'Hello'

def func(x: Any = None) -> Any:
    pass
Enter fullscreen mode Exit fullscreen mode
from typing import Any

v: Any = 'Hello' # `Any` behaves like `str`.

print(v[2])         # No error
print(v.upper())    # No error
print(v + ' World') # No error
Enter fullscreen mode Exit fullscreen mode

<object>:

v: object = 'Hello'

def func(x: object = None) -> object:
    pass
Enter fullscreen mode Exit fullscreen mode
v: object = 'Hello' # `object` behaves like `object`.

print(v[2])         # Error
print(v.upper())    # Error
print(v + ' World') # Error
Enter fullscreen mode Exit fullscreen mode

Setting multiple types to a type hint narrows(limits) the usage of object attributes as shown below:

<str | list[str]>:

*Memo:

  • Both str and list have index() with one required and two optional parameters so index() with one, two or three arguments works.
  • Both str and list have count() but str.count() has one required and two optional parameters while list.count() has one required parameter so count() with one argument works.
  • Only str has upper() so upper() doesn't work.
v: str | list[str] = 'hello world'

print(v.index('rl'))
print(v.index('rl', 6))
print(v.index('rl', 6, 11))
print(v.count('ll'))
# No error

print(v.count('l', 0))
print(v.count('l', 0, 5))
print(v.upper())
# Error

v = ['A', 'B', 'C', 'D', 'E']
# No error
Enter fullscreen mode Exit fullscreen mode

<Cls1 | Cls2>:

*Memo:

  • Both Cls1 and Cls2 have add() but str.add() has x and y required and z optional float parameters while list.add() has a and y required int parameters so add() with two positional or one positional and y keyword int arguments works.
  • Only Cls1 has PI and sub() so PI and sub() don't work.
class Cls1:
    PI: float = 3.14

    def add(self, x:float, y:float, z:float = 4) -> float:
        return x+y+z

    def sub(self, x:float, y:float) -> float:
        return x-y

class Cls2:
    def add(self, a:int, y:int) -> int:
        return a+y

cls1: Cls1 | Cls2 = Cls1()

print(cls1.add(5, 2))
print(cls1.add(5, y=2))
# No error

print(cls1.add(x=5, y=2))
print(cls1.add(5, 2, 6))
print(cls1.add(5.3, 2.8))
print(cls1.PI)
print(cls1.sub(5, 2))
# Error
Enter fullscreen mode Exit fullscreen mode

Top comments (0)