It's also very dynamic as it rarely uses what it knows to limit variable usage. In Python, it's the program's responsibility to use built-in functions like isinstance() and issubclass() to test variable types and correct usage.
var thing = 42; // Java 10 introduced var
System.out.println(thing);
thing = "hello"; // I've got a bad feeling about this...
System.out.println(thing);
Main.java:5: error: incompatible types: String cannot be converted to int
thing = "hello";
Strong or Weak?
Strong
restrictive about how types can be intermingled
Weak
in a weakly typed language a compiler / interpreter will sometimes change the type of a variable
>>> foo = 42>>> bar = 'no thank you'>>> foo + bar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int'and'str'
JavaScript
foo = 42
bar = 'yes please'
foo + bar
> 42yes please // booo
A very well drawn illustration
Review
Python is strongly typed because it restricts how types interact and dynamically typed becuase types are determined and can change at runtime.
Duck Typing
A programming style which does not look at an object’s type to determine if it has the right interface; instead, the method or attribute is simply called or used (“If it looks like a duck and quacks like a duck, it must be a duck.”)
from typing importAny
thing: Any = 1
thing = 2# this is fine
thing = 'hello'# this is fine, too
thing = { 'foo': 'bar' } # totally fine with this
thing = lambda foo: foo.bar() # super fine
defsome_function(data):return data
defsome_typed_function(data: Any) -> Any:return data
defcall_this_funky_func(func):return func()
call_this_funky_func(5) # <- TypeError: 'int' object is not callable
from typing importCallabledefcall_this_typed_funky_func(func: Callable[..., int]):return func()
call_this_typed_funky_func(5) # <- Type "Literal[5]" cannot be assigned to type "(*args: Any, **kwargs: Any) -> int"
call_this_typed_funky_func(lambda: 5)
defcall_this_other_typed_funky_func(func: Callable[[int, int], int]):# do some more interesting stuff...
x = 5
y = 10return func(x, y)
call_this_other_typed_funky_func(lambda x, y: x ** y)
Type variables exist primarily for the benefit of static type checkers. They serve as the parameters for generic types as well as for generic function definitions.
from typing import TypeVar
T = TypeVar('T')
A = TypeVar('A', str, bytes) # Must be str or bytes
from typing import Protocol
# some other moduleclassDuck():defspeak(self):return'Quack!'# our moduleclassSpeaks(Protocol):defspeak(self) -> str: ...
defspeak_louder(speaker: Speaks) -> str:return speaker.speak().upper() + '!'
speak_louder(Duck()) # <-- notice how Duck does not nominally inherit from Speaks
This module defines several types that are subclasses of pre-existing standard library classes which also extend Generic to support type variables inside []. These types became redundant in Python 3.9 when the corresponding pre-existing classes were enhanced to support [].
The redundant types are deprecated as of Python 3.9 but no deprecation warnings will be issued by the interpreter. It is expected that type checkers will flag the deprecated types when the checked program targets Python 3.9 or newer.
The deprecated types will be removed from the typing module in the first Python version released 5 years after the release of Python 3.9.0. See details in PEP 585—Type Hinting Generics In Standard Collections.