Kaleidos.net
Taiga.io
Indicaer el tipo de las "cosas".
Programa encargado de comprobar y aplicar las restricciones de tipos en un código fuente dado.
Las variables poseen un tipo asociado, normalmente explicito aunque a veces inplicito (inferido).
La comprobación de tipos se realiza en tiempo de compilación para poder garantizarlo.
Las variables no poseen un tipo asociado, si no que lo obtienen del valor que contienen en cada momento.
La comprobación de tipos se realiza en tiempo de ejecución.
def validate_entries(entries):
for entry in entries:
entry.data.validate()
"Gradual Typing for Functional Languages"
por Jeremy G. Siek y Walid Taha (2006)
Se permite tanto static typing como dynamic typing en el código.
Utilíza el que quieras cuando quieras.
Hay 3 reglas para conocer la consistencia:
t1
es consistente con un tipo t2
si t1
es un subtipo de t2
(Y no al contrario).Any
es consistente con cualquier typo (Any
no es un subtipo de cualquier tipo).Any
(cualquier tipo no es un subtipo de Any
).
class Employee: ...
class Manager(Employee): ...
worker = Employee() # tipo: Employee
worker = Manager() # OK!: regla 1
boss = Manager() # tipo: Manager
boss = Employee() # Error
something: Any # tipo: Any
worker = something # OK: regla 2
something = boss # OK: regla 3
int # integer
float # floating point number
complex # complex number
# (complex ~ float ~ int)
bool # boolean value
str # unicode string
bytes # 8-bit string
El tipado de las variables puede ser implicito o explicito
a = 3.4 # implicit (float)
b: float = 3.4 # explicit
Y para las clases
from typing import ClassVar
class MyClass:
s: str = 'Gazpachito'
n: int
b: ClassVar[bool] = True
def __init__(self):
self.o: str = 'Espeto'
s = MyClass()
s.s = 1 # Error: Incompatible types in assignment (expression has type "int",
# variable has type "str")
s.o = 2.0 # Error: Incompatible types in assignment (expression has type "float",
# variable has type "str")
MyClass.b = True
s.b = True # Error: Cannot assign to class variable "b" via instance
from typing import Any
something: Any = 1
something = 's'
something = False
something = None
from typing import Any, List
def foo(a: int, b: float, c: List[bool] = [], *d: Any, **e: str) -> bool:
...
foo.__annotations__
# Out: {'a': int,
# 'b': float,
# 'c': typing.List[bool],
# 'd': typing.Any,
# 'e': str,
# 'return': bool}
class Foo:
def do_something(self, i: int):
...
class Bar:
def run(self, x: Foo):
x.od_something(1) # Error: "Foo" has no attribute "od_something"; maybe "do_something"?
Union
sirve para representar un set de tipos válidos.
from typing import Union
def mul(n: int, m: Union[str, int]):
return n * m
mul(5, 1) # -> 5
mul(5, '*') # -> *****
mul(5, 2.0) # Error: Argument 2 to "mul" has incompatible type "float";
# expected "Union[str, int]"
from typing import Any, Optional, Union
assert Union[str] == str
assert Union[str, Any] == Any
assert Union[str, str, int] == Union[str, int]
assert Union[int, str] == Union[str, int]
assert Union[Union[int, str], float] == Union[int, str, float]
assert Union[str, int, None] == Optional[Union[str, int]]
Optional
sirve para indicar que ese valor puede ser None
.
from typing import Optional
z: Optional[str] = None
z = 'text'
El módule typing
contiene generic types de las colecciones más comunes.
from typing import List, Dict, Set, Tuple
List[str] # list of str objects
Dict[str, int] # dictionary from str to int
Set[str] # set of str objects
Tuple[int, int, int] # a 3-tuple of ints
Tuple[int, ...] # a variable length tuple of ints
from typing import List, Set, Union
list_a: List[float]
list_a = [1, 1.0, 2.0]
list_a = ['a', 1.0, 2.0] # Error: List item 0 has incompatible type "str"; expected "float"
list_b: List[Union[float, str]] = [1, 1.0, 'a']
set_a: Set[int] = {1, 2, 3}
set_a = {1, 2, 'a'} # Error: Argument 3 to <set> has incompatible type "str";
# expected "int"
Tambien hay namedtuples()
con la nueva sintaxis.
from typing import NamedTuple
class Employee(NamedTuple):
"""Represents an employee."""
name: str
id: int = 3
def __repr__(self) -> str:
return f'<Employee {self.name}, id={self.id}>'
Tambien están las abstract collections, definidas en collections.abc
(útiles para el duck typing).
from typing import Mapping, MutableMapping, Sequence, MutableSequence
Mapping[str, str] # a mapping from strings to strings
MutableMapping[str, str] # a mutable mapping from strings to strings
Sequence[int] # a sequence of integers
MutableSequence[int] # a mutable sequence of integers
Para definir callbacks, funciones que se pasan como parámetro.
Callable[[int, int], str]
Callable[..., str]
from typing import Callable
def feeder(get_next_item: Callable[[], str]) -> None:
...
def async_query(on_success: Callable[[int], None],
on_error: Callable[[int, Exception], None]) -> None:
...
Sirven para declarar variables de tipo.
from typing import TypeVar
AnyStr = TypeVar('AnyStr', str, bytes) # can be str or bytes
def concat(x: AnyStr, y: AnyStr) -> AnyStr:
return x + y
concat('aaa', 'bbb')
concat(b'aaa', b'bbb')
concat('aaa', b'bbb') # Error: Value of type variable "AnyStr" of "concat" cannot be "object"
NOTA: No te enrolles contando lo de bound
, ni lo de las propiedades covariancia, contravariancia e invarianciaSon clases con uno o más tipos arbitrarios (TypeVar) que serán asignados con su instanciación.
from typing import Generic, List, TypeVar
T = TypeVar('T') # Can be anything
class Stack(Generic[T]):
def __init__(self) -> None:
self.items: List[T] = []
def push(self, item: T) -> None:
self.items.append(item)
def pop(self) -> T:
return self.items.pop()
def empty(self) -> bool:
return not self.items
stacki = Stack[int]()
stacki.push(1)
stacki.push('n') # Error: Argument 1 to "push" of "Stack" has incompatible
# type "str"; expected "int"
@overload
)
type hints
son poco invasibos y pythonicos