Skip to content

Instantly share code, notes, and snippets.

@boredstiff
Created May 16, 2017 03:12
Show Gist options
  • Save boredstiff/bac0ab0df0bec480c1fb0fd67eae0105 to your computer and use it in GitHub Desktop.
Save boredstiff/bac0ab0df0bec480c1fb0fd67eae0105 to your computer and use it in GitHub Desktop.
typing
from typing import (Dict, Tuple, List, NewType, Callable, Mapping, Sequence, TypeVar, Generic,
Iterable)
from logging import Logger
Vector = List[float]
def scale(scalar: float, vector: Vector) -> Vector:
return [scalar * num for num in vector]
new_vector = scale(2.0, [1.0, -4.2, 5.4])
print('new_vector: {}'.format(new_vector))
def greeting(name: str) -> str:
return 'Hello ' + name
print(greeting('Alex'))
# These are type aliases.
ConnectionOptions = Dict[str, str]
Address = Tuple[str, int]
Server = Tuple[Address, ConnectionOptions]
# Notice the Server in here. This is a type alias.
def broadcast_message(message: str, servers: List[Server]) -> None:
print(message)
print(servers)
# The previous type signature is exactly equivalent to this.
def broadcast_message_2(message: str, servers: List[Tuple[Tuple[str, int], Dict[str, str]]]) -> None:
print(message)
print(servers)
# Use NewType() to create distinct types
UserId = NewType('UserId', int)
some_id = UserId(542323)
# The static type checker will treat the new type as if it were a subclass of the original type.
# This is useful in catching logical errors.
def get_user_name(user_id: UserId) -> str:
return 'hello'
# typechecks
user_a = get_user_name(UserId(34234))
# does not typecheck
user_b = get_user_name(-1)
# You can still perform all int operations on UserId, but the result will always be of type int.
# This means you can pass in a UserId wherever an int might be expected, but will prevent you from
# accidentally creating a UserId in an invalid way.
# output is int, not userId
output = UserId(23545) + UserId(757565)
UserId = NewType('UserId', int)
# Fails at runtime and does not typecheck
# class AdminUserId(UserId): pass
# Tells you that the function argument must be code, not str
# Also does not typecheck
ProUserId = NewType('ProUserId', UserId)
# 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. Useful for simplifying complex type signatures.
# NewType declares one type to be a subtype of another.
# NewType('A', B) Means A is a subclass of B.
# This means B cannot be used where A is expected.
def feeder(get_next_item: Callable[[], str]) -> None:
pass
def async_query(on_success: Callable[[int], None], on_error: Callable[[int, Exception], None]) -> None:
pass
Employee = NewType('Employee', str)
# Generics
def notify_by_email(employees: Sequence[Employee],
overrides: Mapping[str, str]) -> None:
pass
# Generics can be parameterized by using a new factory available in typing called TypeVar.
T = TypeVar('T') # Declare type variable
def first(l: Sequence[T]) -> T: # Generic function
return l[0]
class LoggedVar(Generic[T]):
def __init__(self, value: T, name: str, logger: Logger) -> None:
self.name = name
self.logger = logger
self.value = value
def set(self, new: T) -> None:
self.log('Set ' + repr(self.value))
self.value = new
def get(self) -> T:
self.log('Get ' + repr(self.value))
return self.value
def log(self, message: str) -> None:
self.logger.info('%s: %s', self.name, message)
# Generic base class uses a metaclass that defines __getitem__ so that LoggedVar[t] is valid as a type
def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
for var in vars:
var.set(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment