| .. _dynamic_typing: |
| |
| |
| Dynamically typed code |
| ====================== |
| |
| As mentioned earlier, bodies of functions that don't have have any |
| explicit types in their function annotation are dynamically typed |
| (operations are checked at runtime). Code outside functions is |
| statically typed by default, and types of variables are inferred. This |
| does usually the right thing, but you can also make any variable |
| dynamically typed by defining it explicitly with the type ``Any``: |
| |
| .. code-block:: python |
| |
| from typing import Any |
| |
| s = 1 # Statically typed (type int) |
| d = 1 # type: Any # Dynamically typed (type Any) |
| s = 'x' # Type check error |
| d = 'x' # OK |
| |
| Operations on Any values |
| ------------------------ |
| |
| You can do anything using a value with type ``Any``, and type checker |
| does not complain: |
| |
| .. code-block:: python |
| |
| def f(x: Any) -> int: |
| # All of these are valid! |
| x.foobar(1, y=2) |
| print(x[3] + 'f') |
| if x: |
| x.z = x(2) |
| open(x).read() |
| return x |
| |
| Values derived from an ``Any`` value also often have the type ``Any`` |
| implicitly, as mypy can't infer a more precise result type. For |
| example, if you get the attribute of an ``Any`` value or call a |
| ``Any`` value the result is ``Any``: |
| |
| .. code-block:: python |
| |
| def f(x: Any) -> None: |
| y = x.foo() # y has type Any |
| y.bar() # Okay as well! |
| |
| ``Any`` types may propagate through your program, making type checking |
| less effective, unless you are careful. |
| |
| Any vs. object |
| -------------- |
| |
| The type ``object`` is another type that can have an instance of arbitrary |
| type as a value. Unlike ``Any``, ``object`` is an ordinary static type (it |
| is similar to ``Object`` in Java), and only operations valid for *all* |
| types are accepted for ``object`` values. These are all valid: |
| |
| .. code-block:: python |
| |
| def f(o: object) -> None: |
| if o: |
| print(o) |
| print(isinstance(o, int)) |
| o = 2 |
| o = 'foo' |
| |
| These are, however, flagged as errors, since not all objects support these |
| operations: |
| |
| .. code-block:: python |
| |
| def f(o: object) -> None: |
| o.foo() # Error! |
| o + 2 # Error! |
| open(o) # Error! |
| n = 1 # type: int |
| n = o # Error! |
| |
| You can use ``cast()`` (see chapter :ref:`casts`) or ``isinstance`` to |
| go from a general type such as ``object`` to a more specific |
| type (subtype) such as ``int``. ``cast()`` is not needed with |
| dynamically typed values (values with type ``Any``). |