First, "all the errors without having to execute" is a little complicated, even C and C ++ which you mention have errors in runtime and that when compiled are not as explicit and informative as the ones that the Python interpreter shows you .
Now, in the error that I show, I would point out two aspects of Python that we must take into account, the first is that in Python they can add attributes or methods at runtime to a class or an object, so it is going to be difficult for a static analyzer to know whether or not the object has that method at any given time. For good and for bad, Python allows you to do things that are not allowed by C ++ or other compiled languages.
The second one is dynamic typing, strictly in Python the concept of "variable type" does not exist when using C, in Python the "variables" are names that are associated with an object in memory (a int
is an object) and that can be assigned at any given time to another object without problems.
In Python 3 from PEP 483 - The Theory of Type Hints and with the implementation of the annotations has been introduced the possibility to specify the type of a variable / attribute as well as the return and arguments of a function / method.
Do not confuse yourself, Python is still strictly speaking a dynamically typed language and the interpreter does not perform any type checking on its own , but the above allows you to indicate the good reader of our code and tools designed to check types that our variable is expected to have or return our function, allowing a type check prior to generation of the bytecode and its execution.
There are IDEs like PyCharm that have their own type checker, showing you the warning in the editor itself, also based on all the above we have the MyPy project initially developed by DropBox and hosted in the same repository as Python currently, which allows the checking of static types in Python, a small example:
class Button:
def click(self):
print("Click")
class App:
def __init__(self):
self.btn= Button()
app = App()
app.btn.click() # Todo bien
app.btn = [] # Upsss!!!
app.btn.click()
The problem with the previous simple code, which is possibly similar to the problem that caused your error, is that the attribute btn
must be an instance of Button
, not any other thing like a list. There are many ways to validate and handle this at run time, but of course if we take half an hour to execute app.btn = []
, it takes half an hour for the error to appear ...
This is where type annotations and testers like MyPy come in, if we modify the self.btn
statement by adding the corresponding type annotation:
self.btn: Button = Button()
when launching MyPy we will obtain our corresponding typing error without having to execute the code:
$ python -m mypy test.py
test.py:13: error: Incompatible types in assignment
(expression has type "List[<nothing>]", variable has type "Button")
Another example, a function that receives a list of integers or floats and returns the sum of its elements (Python > = 3.5):
from typing import List, Union
def suma(lista: List[Union[int, float]]) -> Union[int, float]:
s = sum(lista)
return s
# Algunas llamadas a la función
suma([1, 2, 3]) # Correcta
suma((1, 2, 3)) # Incorrecta, se le pasa una tupla
suma([1.8, 4, 3]) # Correcta
suma([1.8, "hola", 3]) # Incorrecta, la lista contiene algo que no es int o float
Executing the previous code the interpreter only shows us the expected error when trying to concatenate floats with strings, error that is generated only when that line is executed, not before:
TypeError: unsupported operand type (s) for +: 'float' and 'str'
But MyPy goes further without executing the code showing us the two errors:
$ python -m mypy test.py
test.py:9: error: Argument 1 to "suma" has incompatible type
"Tuple[int, int, int]"; expected "List[Union[int, float]]"
test.py:11: error: List item 1 has incompatible type "str"; expected "float"
All this is relatively new in Python and is currently working on it, for example it is necessary that many third-party libraries implement the check for their own "types", for example imagine the previous case but with an array of NumPy that should contain int8
. Although it seems that the annotations are something superfluous they add a great potential, not only in the shown thing, but it allows for example the optimization of the code in compilers JIT which entailing an improvement in the yield, one of the advantages of the static typing.