Skip to content

Instantly share code, notes, and snippets.

@chadrik
Last active February 25, 2022 05:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chadrik/0b8585589b85aa4fba9f4ef2a952b633 to your computer and use it in GitHub Desktop.
Save chadrik/0b8585589b85aa4fba9f4ef2a952b633 to your computer and use it in GitHub Desktop.
Practical Guide to Python Static Typing
from functools import lru_cache
@lru_cache(None)
def getvalue() -> List[Set[int]]:
return [{1, 2}, {3}]
x = getvalue()
x.append({4})
y = getvalue()
x == y # True! bad!
x is y # True! bad!
from functools import lru_cache
@lru_cache(None)
def getvalue() -> Sequence[AbstractSet[int]]:
return [{1, 2}, {3}]
x = getvalue()
x.append({4}) # mypy errors: no append method
x[0].add(4) # mypy errors: no add method
def get_unique(input: List[str], invalid: List[str]) -> List[str]:
return [x for x in input if x not in invalid]
def get_unique(input: Iterable[str], invalid: Container[str]) -> List[str]:
return [x for x in input if x not in invalid]
if None not in (x, y, z):
result = x + y + z
if x is not None and y is not None and z is not None:
result = x + y + z
inputs = (x, y, z)
valid = [v for v in inputs if v is not None]
if len(valid) == len(inputs):
result = sum(valid)
if inspect.isclass(x) and issubclass(x, Asset):
...
if isinstance(x, type) and issubclass(x, Asset):
...
isAsset = isinstance(x, Asset)
if isAsset:
...
else:
...
if isinstance(x, Asset):
isAsset = True
...
else:
isAsset = False
...
import subprocess
from typing import *
def ls(env: Optional[Dict[str, str]] = None) -> None:
args = "ls -la"
kwargs = {"shell": True} # <-- inferred type is Dict[str, bool] !!!
if env:
kwargs["env"] = env # error! env is not a bool
subprocess.call(args, **kwargs)
import subprocess
from typing import *
def ls(env: Optional[Dict[str, str]] = None) -> None:
args = "ls -la"
kwargs: Dict[str, Any] = {"shell": True}
if env:
kwargs["env"] = env
subprocess.call(args, **kwargs)
if whatever:
foo = 2
else:
foo = 'some string'
if whatever:
foo: Union[int, str] = 2
else:
foo = 'some string'
l1 = [v for k, v in d.items() if k.startswith('foo')]
kwargs = {k: v for k, v in kw.items() if k in _keys}
for i, path in enumerate(paths):
...
for i, item in enumerate(items): # ok! i is still an int
...
import subprocess
from typing import *
def run(args: Union[str, List[str]], env: Optional[Dict[str, str]] = None) -> None:
kwargs: Dict[str, Any] = {
"shell": False,
}
if isinstance(args, str):
# in this scope, args is understood to be a str
args = args.split() # convert from str to List[str]. the str case of Union[str, List[str]] is now removed
# at this point args can now only be List[str]
if env:
kwargs["env"] = env
subprocess.call(args, **kwargs)
import subprocess
from typing import *
def run(args: str, env: Optional[Dict[str, str]] = None) -> None:
kwargs: Dict[str, Any] = {
"shell": False,
}
args = args.split() # can't reassign the type of args!
args.insert(0, 'xdg-open')
if env:
kwargs["env"] = env
subprocess.call(args, **kwargs)
import subprocess
from typing import *
def run(command: str, env: Optional[Dict[str, str]] = None) -> None:
kwargs: Dict[str, Any] = {
"shell": False,
}
args = command.split()
args.insert(0, 'xdg-open')
if env:
kwargs["env"] = env
subprocess.call(args, **kwargs)
def letter_list(s: str, strip_last: bool = False) -> Optional[str]:
if s:
result = list(s)
if strip_last:
result = result[:-1]
else:
result = None # <--- error: incompatible type
return result
def letter_list(s: str, strip_last: bool = False) -> Optional[str]:
if s:
result: Optional[str] = list(s)
if strip_last:
result = result[:-1] # <--- error: None does not support indexing
else:
result = None
return result
def letter_list(s: str, strip_last: bool = False) -> Optional[str]:
if s:
result = list(s)
if strip_last:
result = result[:-1]
return result
else:
return None
class Base:
validThings = ('thing1',)
class A(Base):
validThings = ('thing1', 'thing2')
class Base:
validThings: Tuple[str, ...] = ('thing1',)
class A(Base):
validThings: Tuple[str, ...] = ('thing1', 'thing2')
class Base:
validThings = FrozenSet(['thing1'])
class A(Base):
validThings = FrozenSet(['thing1', 'thing2'])
class Base:
validThings: Final[List[str]] = ['thing1']
class A(Base):
validThings: Final[List[str]] = ['thing1', 'thing2']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment