Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type hints: Is it a bad practice to alias primitive data types?

In Python documentation for typing & type hints we have the below example:

Vector = List[float]

def scale(scalar: float, vector: Vector) -> Vector:
    return [scalar * num for num in vector]

Vector type alias clearly shows that type aliases are useful for simplifying complex type signatures.

However, what about aliasing primitive data types?

Let's contrast two basic examples of function signatures:

URL = str    

def process_url(url: URL) -> URL:
    pass

vs.

def process_url(url: str) -> str:
    pass

Version with type alias URL for primitive type str is:

  • self-documenting (among others, now I can skip documenting returned value, as it should be clearly an url),
  • resistant to type implementation change (I can switch URL to be Dict or namedtuple later on without changing functions signatures).

The problem is I cannot find anyone else following such practice. I am simply afraid that I am unintentionally abusing type hints to implement my own ideas instead of following their intended purpose.


Note from 2020-10

Python 3.9 introduces "flexible function and variable annotations", which allows to make annotations like:

def speed_1(distance: "feet", time: "seconds") -> "miles per hour":
    pass

def speed_2(
    distance: Annotated[float, "feet"], time: Annotated[float, "seconds"]
) -> Annotated[float, "miles per hour"]:
    pass

Which renders aliasing data types for documenting purposes rather redundant!

See:

  • https://www.python.org/dev/peps/pep-0593/
  • https://realpython.com/python39-new-features/#annotated-type-hints
like image 234
CapedHero Avatar asked Sep 25 '18 18:09

CapedHero


People also ask

Is it good practice to use type hints in Python?

Type hints work best in modern Pythons. Annotations were introduced in Python 3.0, and it's possible to use type comments in Python 2.7. Still, improvements like variable annotations and postponed evaluation of type hints mean that you'll have a better experience doing type checks using Python 3.6 or even Python 3.7.

What are reasons for using type hinting?

Introduction to Type Hints As the code base gets larger, type hints can help to debug and prevent some dumb mistakes. If you're using an IDE like PyCharm, you'll get a warning message whenever you've used the wrong data type, provided you're using type hints.


1 Answers

Using an alias to mark the meaning of a value can be misleading and dangerous. If only a subset of values are valid, a NewType should be used instead.

Recall that the use of a type alias declares two types to be equivalent to one another. Doing Alias = Original will make the static type checker treat Alias as being exactly equivalent to Original in all cases. This is useful when you want to simplify complex type signatures.

Simple aliasing works both ways: the alias URL = str means any URL is a str and also means any str is a URL – which is usually not correct: A URL is a special kind of str and not any can take its place. An alias URL = str is a too strong statement of equality, as it cannot express this distinction. In fact, any inspection that does not look at the source code does not see the distinction:

In [1]: URL = str
In [2]: def foo(bar: URL):
   ...:     pass
   ...:
In [3]: foo?
Signature: foo(bar: str)

Consider that you alias Celsius = float in one module, and Fahrenheit = float in another. This signals that it is valid to use Celsius as Fahrenheit, which is wrong.

Unless your types do cary separative meaning, you should just take a url: str. The name signifies the meaning, the type the valid values. That means that your type should be suitable to separate valid and invalid values!

Use aliases to shorten your hints, but use NewType to refine them.

Vector = List[float]        # alias shortens
URL = NewType("URL", str)   # new type separates
like image 184
MisterMiyagi Avatar answered Oct 25 '22 11:10

MisterMiyagi