CONTENTS
1 What’s New In Python 3 3
2 Cheat Sheet 21
3 Advanced Cheat Sheet 135
4 Appendix 339
i
ii
python-cheatsheet Documentation, Release 0.1.0
Welcome to pysheeet. This project aims at collecting useful Python snippets in order to enhance pythoneers’ coding ex-
periences. Please feel free to contribute if you have any awesome ideas for improvements to code snippets, explanations,
etc.
Any snippets are welcome. If you’d like to contribute, fork pysheeet on GitHub. If there is any question or suggestion,
please create an issue on GitHub Issues.
CONTENTS 1
python-cheatsheet Documentation, Release 0.1.0
2 CONTENTS
CHAPTER
ONE
WHAT’S NEW IN PYTHON 3
The official document, What’s New In Python, displays all of the most important changes. However, if you’re too busy
to read the whole changes, this part provides a brief glance of new features in Python 3.
1.1 New in Python3
Table of Contents
• New in Python3
– print is a function
– String is unicode
– Division Operator
– New dict implementation
– Keyword-Only Arguments
– New Super
– Remove <>
– BDFL retirement
– Not allow from module import * inside function
– Add nonlocal keyword
– Extended iterable unpacking
– General unpacking
– Function annotations
– Variable annotations
– Core support for typing module and generic types
– Format byte string
– fstring
– Suppressing exception
– Generator delegation
– async and await syntax
3
python-cheatsheet Documentation, Release 0.1.0
– Asynchronous generators
– Asynchronous comprehensions
– Matrix multiplication
– Data Classes
– Built-in breakpoint()
– The walrus operator
– Positional-only parameters
– Dictionary Merge
1.1.1 print is a function
New in Python 3.0
• PEP 3105 - Make print a function
Python 2
>>> print "print is a statement"
print is a statement
>>> for x in range(3):
... print x,
...
0 1 2
Python 3
>>> print("print is a function")
print is a function
>>> print()
>>> for x in range(3):
... print(x, end=' ')
... else:
... print()
...
0 1 2
1.1.2 String is unicode
New in Python 3.0
• PEP 3138 - String representation in Python 3000
• PEP 3120 - Using UTF-8 as the default source encoding
• PEP 3131 - Supporting Non-ASCII Identifiers
Python 2
4 Chapter 1. What’s New In Python 3
python-cheatsheet Documentation, Release 0.1.0
>>> s = 'Café' # byte string
>>> s
'Caf\xc3\xa9'
>>> type(s)
<type 'str'>
>>> u = u'Café' # unicode string
>>> u
u'Caf\xe9'
>>> type(u)
<type 'unicode'>
>>> len([_c for _c in 'Café'])
5
Python 3
>>> s = 'Café'
>>> s
'Café'
>>> type(s)
<class 'str'>
>>> s.encode('utf-8')
b'Caf\xc3\xa9'
>>> s.encode('utf-8').decode('utf-8')
'Café'
>>> len([_c for _c in 'Café'])
4
1.1.3 Division Operator
New in Python 3.0
• PEP 238 - Changing the Division Operator
Python2
>>> 1 / 2
0
>>> 1 // 2
0
>>> 1. / 2
0.5
# back port "true division" to python2
>>> from __future__ import division
>>> 1 / 2
0.5
>>> 1 // 2
0
Python3
1.1. New in Python3 5
python-cheatsheet Documentation, Release 0.1.0
>>> 1 / 2
0.5
>>> 1 // 2
0
1.1.4 New dict implementation
New in Python 3.6
• PEP 468 - Preserving the order of **kwargs in a function
• PEP 520 - Preserving Class Attribute Definition Order
• bpo 27350 - More compact dictionaries with faster iteration
Before Python 3.5
>>> import sys
>>> sys.getsizeof({str(i):i for i in range(1000)})
49248
>>> d = {'timmy': 'red', 'barry': 'green', 'guido': 'blue'}
>>> d # without order-preserving
{'barry': 'green', 'timmy': 'red', 'guido': 'blue'}
Python 3.6
• Memory usage is smaller than Python 3.5
• Preserve insertion ordered
>>> import sys
>>> sys.getsizeof({str(i):i for i in range(1000)})
36968
>>> d = {'timmy': 'red', 'barry': 'green', 'guido': 'blue'}
>>> d # preserve insertion ordered
{'timmy': 'red', 'barry': 'green', 'guido': 'blue'}
1.1.5 Keyword-Only Arguments
New in Python 3.0
• PEP 3102 - Keyword-Only Arguments
>>> def f(a, b, *, kw):
... print(a, b, kw)
...
>>> f(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 2 positional arguments but 3 were given
>>> f(1, 2)
Traceback (most recent call last):
(continues on next page)
6 Chapter 1. What’s New In Python 3
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
File "<stdin>", line 1, in <module>
TypeError: f() missing 1 required keyword-only argument: 'kw'
>>> f(1, 2, kw=3)
1 2 3
1.1.6 New Super
New in Python 3.0
• PEP 3135 - New Super
Python 2
>>> class ParentCls(object):
... def foo(self):
... print "call parent"
...
>>> class ChildCls(ParentCls):
... def foo(self):
... super(ChildCls, self).foo()
... print "call child"
...
>>> p = ParentCls()
>>> c = ChildCls()
>>> p.foo()
call parent
>>> c.foo()
call parent
call child
Python 3
>>> class ParentCls(object):
... def foo(self):
... print("call parent")
...
>>> class ChildCls(ParentCls):
... def foo(self):
... super().foo()
... print("call child")
...
>>> p = ParentCls()
>>> c = ChildCls()
>>> p.foo()
call parent
>>> c.foo()
call parent
call child
1.1. New in Python3 7
python-cheatsheet Documentation, Release 0.1.0
1.1.7 Remove <>
New in Python 3.0
Python 2
>>> a = "Python2"
>>> a <> "Python3"
True
# equal to !=
>>> a != "Python3"
True
Python 3
>>> a = "Python3"
>>> a != "Python2"
True
1.1.8 BDFL retirement
New in Python 3.1
• PEP 401 - BDFL Retirement
>>> from __future__ import barry_as_FLUFL
>>> 1 != 2
File "<stdin>", line 1
1 != 2
^
SyntaxError: with Barry as BDFL, use '<>' instead of '!='
>>> 1 <> 2
True
1.1.9 Not allow from module import * inside function
New in Python 3.0
>>> def f():
... from os import *
...
File "<stdin>", line 1
SyntaxError: import * only allowed at module level
8 Chapter 1. What’s New In Python 3
python-cheatsheet Documentation, Release 0.1.0
1.1.10 Add nonlocal keyword
New in Python 3.0
PEP 3104 - Access to Names in Outer Scopes
Note: nonlocal allow assigning directly to a variable in an outer (but non-global) scope
>>> def outf():
... o = "out"
... def inf():
... nonlocal o
... o = "change out"
... inf()
... print(o)
...
>>> outf()
change out
1.1.11 Extended iterable unpacking
New in Python 3.0
• PEP 3132 - Extended Iterable Unpacking
>>> a, *b, c = range(5)
>>> a, b, c
(0, [1, 2, 3], 4)
>>> for a, *b in [(1, 2, 3), (4, 5, 6, 7)]:
... print(a, b)
...
1 [2, 3]
4 [5, 6, 7]
1.1.12 General unpacking
New in Python 3.5
• PEP 448 - Additional Unpacking Generalizations
Python 2
>>> def func(*a, **k):
... print(a)
... print(k)
...
>>> func(*[1,2,3,4,5], **{"foo": "bar"})
(1, 2, 3, 4, 5)
{'foo': 'bar'}
Python 3
1.1. New in Python3 9
python-cheatsheet Documentation, Release 0.1.0
>>> print(*[1, 2, 3], 4, *[5, 6])
1 2 3 4 5 6
>>> [*range(4), 4]
[0, 1, 2, 3, 4]
>>> {"foo": "Foo", "bar": "Bar", **{"baz": "baz"}}
{'foo': 'Foo', 'bar': 'Bar', 'baz': 'baz'}
>>> def func(*a, **k):
... print(a)
... print(k)
...
>>> func(*[1], *[4,5], **{"foo": "FOO"}, **{"bar": "BAR"})
(1, 4, 5)
{'foo': 'FOO', 'bar': 'BAR'}
1.1.13 Function annotations
New in Python 3.0
• PEP 3107 - Function Annotations
• PEP 484 - Type Hints
• PEP 483 - The Theory of Type Hints
>>> import types
>>> generator = types.GeneratorType
>>> def fib(n: int) -> generator:
... a, b = 0, 1
... for _ in range(n):
... yield a
... b, a = a + b, b
...
>>> [f for f in fib(10)]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
1.1.14 Variable annotations
New in Python 3.6
• PEP 526 - Syntax for Variable Annotations
>>> from typing import List
>>> x: List[int] = [1, 2, 3]
>>> x
[1, 2, 3]
>>> from typing import List, Dict
>>> class Cls(object):
... x: List[int] = [1, 2, 3]
... y: Dict[str, str] = {"foo": "bar"}
...
>>> o = Cls()
(continues on next page)
10 Chapter 1. What’s New In Python 3
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
>>> o.x
[1, 2, 3]
>>> o.y
{'foo': 'bar'}
1.1.15 Core support for typing module and generic types
New in Python 3.7
• PEP 560 - Core support for typing module and generic types
Before Python 3.7
>>> from typing import Generic, TypeVar
>>> from typing import Iterable
>>> T = TypeVar('T')
>>> class C(Generic[T]): ...
...
>>> def func(l: Iterable[C[int]]) -> None:
... for i in l:
... print(i)
...
>>> func([1,2,3])
1
2
3
Python 3.7 or above
>>> from typing import Iterable
>>> class C:
... def __class_getitem__(cls, item):
... return f"{cls.__name__}[{item.__name__}]"
...
>>> def func(l: Iterable[C[int]]) -> None:
... for i in l:
... print(i)
...
>>> func([1,2,3])
1
2
3
1.1. New in Python3 11
python-cheatsheet Documentation, Release 0.1.0
1.1.16 Format byte string
New in Python 3.5
• PEP 461 - Adding % formatting to bytes and bytearray
>>> b'abc %b %b' % (b'foo', b'bar')
b'abc foo bar'
>>> b'%d %f ' % (1, 3.14)
b'1 3.140000'
>>> class Cls(object):
... def __repr__(self):
... return "repr"
... def __str__(self):
... return "str"
...
'repr'
>>> b'%a' % Cls()
b'repr'
1.1.17 fstring
New in Python 3.6
• PEP 498 - Literal String Interpolation
>>> py = "Python3"
>>> f'Awesome {py}'
'Awesome Python3'
>>> x = [1, 2, 3, 4, 5]
>>> f'{x}'
'[1, 2, 3, 4, 5]'
>>> def foo(x:int) -> int:
... return x + 1
...
>>> f'{foo(0)}'
'1'
>>> f'{123.567:1.3}'
'1.24e+02'
1.1.18 Suppressing exception
New in Python 3.3
• PEP 409 - Suppressing exception context
Without raise Exception from None
>>> def func():
... try:
... 1 / 0
... except ZeroDivisionError:
... raise ArithmeticError
(continues on next page)
12 Chapter 1. What’s New In Python 3
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
...
>>> func()
Traceback (most recent call last):
File "<stdin>", line 3, in func
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in func
ArithmeticError
With raise Exception from None
>>> def func():
... try:
... 1 / 0
... except ZeroDivisionError:
... raise ArithmeticError from None
...
>>> func()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in func
ArithmeticError
# debug
>>> try:
... func()
... except ArithmeticError as e:
... print(e.__context__)
...
division by zero
1.1.19 Generator delegation
New in Python 3.3
• PEP 380 - Syntax for Delegating to a Subgenerator
>>> def fib(n: int):
... a, b = 0, 1
... for _ in range(n):
... yield a
... b, a = a + b, b
...
>>> def delegate(n: int):
... yield from fib(n)
...
(continues on next page)
1.1. New in Python3 13
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
>>> list(delegate(10))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
1.1.20 async and await syntax
New in Python 3.5
• PEP 492 - Coroutines with async and await syntax
Before Python 3.5
>>> import asyncio
>>> @asyncio.coroutine
... def fib(n: int):
... a, b = 0, 1
... for _ in range(n):
... b, a = a + b, b
... return a
...
>>> @asyncio.coroutine
... def coro(n: int):
... for x in range(n):
... yield from asyncio.sleep(1)
... f = yield from fib(x)
... print(f)
...
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(coro(3))
0
1
1
Python 3.5 or above
>>> import asyncio
>>> async def fib(n: int):
... a, b = 0, 1
... for _ in range(n):
... b, a = a + b, b
... return a
...
>>> async def coro(n: int):
... for x in range(n):
... await asyncio.sleep(1)
... f = await fib(x)
... print(f)
...
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(coro(3))
0
1
1
14 Chapter 1. What’s New In Python 3
python-cheatsheet Documentation, Release 0.1.0
1.1.21 Asynchronous generators
New in Python 3.6
• PEP 525 - Asynchronous Generators
>>> import asyncio
>>> async def fib(n: int):
... a, b = 0, 1
... for _ in range(n):
... await asyncio.sleep(1)
... yield a
... b, a = a + b , b
...
>>> async def coro(n: int):
... ag = fib(n)
... f = await ag.asend(None)
... print(f)
... f = await ag.asend(None)
... print(f)
...
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(coro(5))
0
1
1.1.22 Asynchronous comprehensions
New in Python 3.6
• PEP 530 - Asynchronous Comprehensions
>>> import asyncio
>>> async def fib(n: int):
... a, b = 0, 1
... for _ in range(n):
... await asyncio.sleep(1)
... yield a
... b, a = a + b , b
...
# async for ... else
>>> async def coro(n: int):
... async for f in fib(n):
... print(f, end=" ")
... else:
... print()
...
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(coro(5))
0 1 1 2 3
(continues on next page)
1.1. New in Python3 15
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
# async for in list
>>> async def coro(n: int):
... return [f async for f in fib(n)]
...
>>> loop.run_until_complete(coro(5))
[0, 1, 1, 2, 3]
# await in list
>>> async def slowfmt(n: int) -> str:
... await asyncio.sleep(0.5)
... return f'{n}'
...
>>> async def coro(n: int):
... return [await slowfmt(f) async for f in fib(n)]
...
>>> loop.run_until_complete(coro(5))
['0', '1', '1', '2', '3']
1.1.23 Matrix multiplication
New in Python 3.5
• PEP 465 - A dedicated infix operator for matrix multiplication
>>> # "@" represent matrix multiplication
>>> class Arr:
... def __init__(self, *arg):
... self._arr = arg
... def __matmul__(self, other):
... if not isinstance(other, Arr):
... raise TypeError
... if len(self) != len(other):
... raise ValueError
... return sum([x*y for x, y in zip(self._arr, other._arr)])
... def __imatmul__(self, other):
... if not isinstance(other, Arr):
... raise TypeError
... if len(self) != len(other):
... raise ValueError
... res = sum([x*y for x, y in zip(self._arr, other._arr)])
... self._arr = [res]
... return self
... def __len__(self):
... return len(self._arr)
... def __str__(self):
... return self.__repr__()
... def __repr__(self):
... return "Arr({})".format(repr(self._arr))
...
(continues on next page)
16 Chapter 1. What’s New In Python 3
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
>>> a = Arr(9, 5, 2, 7)
>>> b = Arr(5, 5, 6, 6)
>>> a @ b # __matmul__
124
>>> a @= b # __imatmul__
>>> a
Arr([124])
1.1.24 Data Classes
New in Python 3.7
PEP 557 - Data Classes
Mutable Data Class
>>> from dataclasses import dataclass
>>> @dataclass
... class DCls(object):
... x: str
... y: str
...
>>> d = DCls("foo", "bar")
>>> d
DCls(x='foo', y='bar')
>>> d = DCls(x="foo", y="baz")
>>> d
DCls(x='foo', y='baz')
>>> d.z = "bar"
Immutable Data Class
>>> from dataclasses import dataclass
>>> from dataclasses import FrozenInstanceError
>>> @dataclass(frozen=True)
... class DCls(object):
... x: str
... y: str
...
>>> try:
... d.x = "baz"
... except FrozenInstanceError as e:
... print(e)
...
cannot assign to field 'x'
>>> try:
... d.z = "baz"
... except FrozenInstanceError as e:
... print(e)
...
cannot assign to field 'z'
1.1. New in Python3 17
python-cheatsheet Documentation, Release 0.1.0
1.1.25 Built-in breakpoint()
New in Python 3.7
• PEP 553 - Built-in breakpoint()
>>> for x in range(3):
... print(x)
... breakpoint()
...
0
> <stdin>(1)<module>()->None
(Pdb) c
1
> <stdin>(1)<module>()->None
(Pdb) c
2
> <stdin>(1)<module>()->None
(Pdb) c
1.1.26 The walrus operator
New in Python 3.8
• PEP 572 - Assignment Expressions
The goal of the walrus operator is to assign variables within an expression. After completing PEP 572, Guido van
Rossum, commonly known as BDFL, decided to resign as a Python dictator.
>>> f = (0, 1)
>>> [(f := (f[1], sum(f)))[0] for i in range(10)]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
1.1.27 Positional-only parameters
New in Python 3.8
• PEP 570 - Python Positional-Only Parameters
>>> def f(a, b, /, c, d):
... print(a, b, c, d)
...
>>> f(1, 2, 3, 4)
1 2 3 4
>>> f(1, 2, c=3, d=4)
1 2 3 4
>>> f(1, b=2, c=3, d=4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() got some positional-only arguments passed as keyword arguments: 'b'
18 Chapter 1. What’s New In Python 3
python-cheatsheet Documentation, Release 0.1.0
1.1.28 Dictionary Merge
New in Python 3.9
• PEP 584 - Add Union Operators To dict
>>> a = {"foo": "Foo"}
>>> b = {"bar": "Bar"}
# old way
>>> {**a, **b}
{'foo': 'Foo', 'bar': 'Bar'}
>>> a.update(b)
>>> a
{'foo': 'Foo', 'bar': 'Bar'}
# new way
>>> a | b
{'foo': 'Foo', 'bar': 'Bar'}
>>> a |= b
>>> a
{'foo': 'Foo', 'bar': 'Bar'}
1.1. New in Python3 19
python-cheatsheet Documentation, Release 0.1.0
20 Chapter 1. What’s New In Python 3
CHAPTER
TWO
CHEAT SHEET
This part mainly focuses on common snippets in Python code. The cheat sheet not only includes basic Python features
but also data structures and algorithms.
2.1 Style
Table of Contents
• Style
– Naming
∗ Class
∗ Function
∗ Variable
2.1.1 Naming
Class
Bad
class fooClass: ...
class foo_class: ...
Good
class FooClass: ...
21
python-cheatsheet Documentation, Release 0.1.0
Function
Bad
def CapCamelCase(*a): ...
def mixCamelCase(*a): ...
Good
def func_separated_by_underscores(*a): ...
Variable
Bad
FooVar = "CapWords"
fooVar = "mixedCase"
Foo_Var = "CapWords_With_Underscore"
Good
# local variable
var = "lowercase"
# internal use
_var = "_single_leading_underscore"
# avoid conflicts with Python keyword
var_ = "single_trailing_underscore_"
# a class attribute (private use in class)
__var = " __double_leading_underscore"
# "magic" objects or attributes, ex: __init__
__name__
# throwaway variable, ex: _, v = (1, 2)
_ = "throwaway"
2.2 From Scratch
The main goal of this cheat sheet is to collect some common and basic semantics or snippets. The cheat sheet includes
some syntax, which we have already known but still ambiguous in our mind, or some snippets, which we google them
again and again. In addition, because the end Of life date for Python 2 is coming. Most of the snippets are mainly
based on Python 3’s syntax.
Table of Contents
• From Scratch
– Hello world!
22 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
– Python Version
– Ellipsis
– if . . . elif . . . else
– for Loop
– for . . . else . . .
– Using range
– while . . . else . . .
– The do while Statement
– try . . . except . . . else . . .
– String
– List
– Dict
– Function
– Function Annotations
– Generators
– Generator Delegation
– Class
– async / await
– Avoid exec and eval
2.2.1 Hello world!
When we start to learn a new language, we usually learn from printing Hello world!. In Python, we can use another
way to print the message by importing __hello__ module. The source code can be found on frozen.c.
>>> print("Hello world!")
Hello world!
>>> import __hello__
Hello world!
>>> import __phello__
Hello world!
>>> import __phello__.spam
Hello world!
2.2. From Scratch 23
python-cheatsheet Documentation, Release 0.1.0
2.2.2 Python Version
It is important for a programmer to know current Python version because not every syntax will work in the current
version. In this case, we can get the Python version by python -V or using the module, sys.
>>> import sys
>>> print(sys.version)
3.7.1 (default, Nov 6 2018, 18:46:03)
[Clang 10.0.0 (clang-1000.11.45.5)]
We can also use platform.python_version to get Python version.
>>> import platform
>>> platform.python_version()
'3.7.1'
Sometimes, checking the current Python version is important because we may want to enable some features in some
specific versions. sys.version_info provides more detail information about the interpreter. We can use it to compare
with the version we want.
>>> import sys
>>> sys.version_info >= (3, 6)
True
>>> sys.version_info >= (3, 7)
False
2.2.3 Ellipsis
Ellipsis is a built-in constant. After Python 3.0, we case use ... as Ellipsis. It may be the most enigmatic constant
in Python. Based on the official document, we can use it to extend slicing syntax. Nevertheless, there are some other
conventions in type hinting, stub files, or function expressions.
>>> ...
Ellipsis
>>> ... == Ellipsis
True
>>> type(...)
<class 'ellipsis'>
The following snippet shows that we can use the ellipsis to represent a function or a class which has not implemented
yet.
>>> class Foo: ...
...
>>> def foo(): ...
...
24 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.2.4 if . . . elif . . . else
The if statements are used to control the code flow. Instead of using switch or case statements control the logic of
the code, Python uses if ... elif ... else sequence. Although someone proposes we can use dict to achieve
switch statements, this solution may introduce unnecessary overhead such as creating disposable dictionaries and
undermine a readable code. Thus, the solution is not recommended.
>>> import random
>>> num = random.randint(0, 10)
>>> if num < 3:
... print("less than 3")
... elif num < 5:
... print("less than 5")
... else:
... print(num)
...
less than 3
2.2.5 for Loop
In Python, we can access iterable object’s items directly through the for statement. If we need to get indexes and items
of an iterable object such as list or tuple at the same time, using enumerate is better than range(len(iterable)).
Further information can be found on Looping Techniques.
>>> for val in ["foo", "bar"]:
... print(val)
...
foo
bar
>>> for idx, val in enumerate(["foo", "bar", "baz"]):
... print(idx, val)
...
(0, 'foo')
(1, 'bar')
(2, 'baz')
2.2.6 for . . . else . . .
It may be a little weird when we see the else belongs to a for loop at the first time. The else clause can assist us to
avoid using flag variables in loops. A loop’s else clause runs when no break occurs.
>>> for _ in range(5):
... pass
... else:
... print("no break")
...
no break
The following snippet shows the difference between using a flag variable and the else clause to control the loop. We
can see that the else does not run when the break occurs in the loop.
2.2. From Scratch 25
python-cheatsheet Documentation, Release 0.1.0
>>> is_break = False
>>> for x in range(5):
... if x % 2 == 0:
... is_break = True
... break
...
>>> if is_break:
... print("break")
...
break
>>> for x in range(5):
... if x % 2 == 0:
... print("break")
... break
... else:
... print("no break")
...
break
2.2.7 Using range
The problem of range in Python 2 is that range may take up a lot of memory if we need to iterate a loop many times.
Consequently, using xrange is recommended in Python 2.
>>> import platform
>>> import sys
>>> platform.python_version()
'2.7.15'
>>> sys.getsizeof(range(100000000))
800000072
>>> sys.getsizeof(xrange(100000000))
40
In Python 3, the built-in function range returns an iterable range object instead of a list. The behavior of range is
the same as the xrange in Python 2. Therefore, using range do not take up huge memory anymore if we want to run
a code block many times within a loop. Further information can be found on PEP 3100.
>>> import platform
>>> import sys
>>> platform.python_version()
'3.7.1'
>>> sys.getsizeof(range(100000000))
48
26 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.2.8 while . . . else . . .
The else clause belongs to a while loop serves the same purpose as the else clause in a for loop. We can observe that
the else does not run when the break occurs in the while loop.
>>> n = 0
>>> while n < 5:
... if n == 3:
... break
... n += 1
... else:
... print("no break")
...
2.2.9 The do while Statement
There are many programming languages such as C/C++, Ruby, or Javascript, provide the do while statement. In
Python, there is no do while statement. However, we can place the condition and the break at the end of a while
loop to achieve the same thing.
>>> n = 0
>>> while True:
... n += 1
... if n == 5:
... break
...
>>> n
5
2.2.10 try . . . except . . . else . . .
Most of the time, we handle errors in except clause and clean up resources in finally clause. Interestingly, the try
statement also provides an else clause for us to avoid catching an exception which was raised by the code that should
not be protected by try ... except. The else clause runs when no exception occurs between try and except.
>>> try:
... print("No exception")
... except:
... pass
... else:
... print("Success")
...
No exception
Success
2.2. From Scratch 27
python-cheatsheet Documentation, Release 0.1.0
2.2.11 String
Unlike other programming languages, Python does not support string’s item assignment directly. Therefore, if it is
necessary to manipulate string’s items, e.g., swap items, we have to convert a string to a list and do a join operation
after a series item assignments finish.
>>> a = "Hello Python"
>>> l = list(a)
>>> l[0], l[6] = 'h', 'p'
>>> ''.join(l)
'hello python'
2.2.12 List
Lists are versatile containers. Python provides a lot of ways such as negative index, slicing statement, or list com-
prehension to manipulate lists. The following snippet shows some common operations of lists.
>>> a = [1, 2, 3, 4, 5]
>>> a[-1] # negative index
5
>>> a[1:] # slicing
[2, 3, 4, 5]
>>> a[1:-1]
[2, 3, 4]
>>> a[1:-1:2]
[2, 4]
>>> a[::-1] # reverse
[5, 4, 3, 2, 1]
>>> a[0] = 0 # set an item
>>> a
[0, 2, 3, 4, 5]
>>> a.append(6) # append an item
>>> a
[0, 2, 3, 4, 5, 6]
>>> del a[-1] # del an item
>>> a
[0, 2, 3, 4, 5]
>>> b = [x for x in range(3)] # list comprehension
>>> b
[0, 1, 2]
>>> a + b # add two lists
[0, 2, 3, 4, 5, 0, 1, 2]
28 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.2.13 Dict
Dictionaries are key-value pairs containers. Like lists, Python supports many ways such as dict comprehensions to
manipulate dictionaries. After Python 3.6, dictionaries preserve the insertion order of keys. The Following snippet
shows some common operations of dictionaries.
>>> d = {'timmy': 'red', 'barry': 'green', 'guido': 'blue'}
>>> d
{'timmy': 'red', 'barry': 'green', 'guido': 'blue'}
>>> d['timmy'] = "yellow" # set data
>>> d
{'timmy': 'yellow', 'barry': 'green', 'guido': 'blue'}
>>> del d['guido'] # del data
>>> d
>>> 'guido' in d # contain data
False
{'timmy': 'yellow', 'barry': 'green'}
>>> {k: v for k ,v in d.items()} # dict comprehension
{'timmy': 'yellow', 'barry': 'green'}
>>> d.keys() # list all keys
dict_keys(['timmy', 'barry'])
>>> d.values() # list all values
dict_values(['yellow', 'green'])
2.2.14 Function
Defining a function in Python is flexible. We can define a function with function documents, default values, arbitrary
arguments, keyword arguments, keyword-only arguments, and so on. The Following snippet shows some common
expressions to define functions.
def foo_with_doc():
"""Documentation String."""
def foo_with_arg(arg): ...
def foo_with_args(*arg): ...
def foo_with_kwarg(a, b="foo"): ...
def foo_with_args_kwargs(*args, **kwargs): ...
def foo_with_kwonly(a, b, *, k): ... # python3
def foo_with_annotations(a: int) -> int: ... # python3
2.2.15 Function Annotations
Instead of writing string documents in functions to hint the type of parameters and return values, we can denote types by
function annotations. Function annotations which the details can be found on PEP 3017 and PEP 484 were introduced
in Python 3.0. They are an optional feature in Python 3. Using function annotations will lose compatibility in Python
2. We can solve this issue by stub files. In addition, we can do static type checking through mypy.
>>> def fib(n: int) -> int:
... a, b = 0, 1
... for _ in range(n):
... b, a = a + b, b
(continues on next page)
2.2. From Scratch 29
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
... return a
...
>>> fib(10)
55
2.2.16 Generators
Python uses the yield statement to define a generator function. In other words, when we call a generator function,
the generator function will return a generator instead of return values for creating an iterator.
>>> def fib(n):
... a, b = 0, 1
... for _ in range(n):
... yield a
... b, a = a + b, b
...
>>> g = fib(10)
>>> g
<generator object fib at 0x10b240c78>
>>> for f in fib(5):
... print(f)
...
0
1
1
2
3
2.2.17 Generator Delegation
Python 3.3 introduced yield from expression. It allows a generator to delegate parts of operations to another gen-
erator. In other words, we can yield a sequence from other generators in the current generator function. Further
information can be found on PEP 380.
>>> def fib(n):
... a, b = 0, 1
... for _ in range(n):
... yield a
... b, a = a + b, b
...
>>> def fibonacci(n):
... yield from fib(n)
...
>>> [f for f in fibonacci(5)]
[0, 1, 1, 2, 3]
30 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.2.18 Class
Python supports many common features such as class documents, multiple inheritance, class variables, instance
variables, static method, class method, and so on. Furthermore, Python provides some special methods for program-
mers to implement iterators, context manager, etc. The following snippet displays common definition of a class.
class A: ...
class B: ...
class Foo(A, B):
"""A class document."""
foo = "class variable"
def __init__(self, v):
self.attr = v
self.__private = "private var"
@staticmethod
def bar_static_method(): ...
@classmethod
def bar_class_method(cls): ...
def bar(self):
"""A method document."""
def bar_with_arg(self, arg): ...
def bar_with_args(self, *args): ...
def bar_with_kwarg(self, kwarg="bar"): ...
def bar_with_args_kwargs(self, *args, **kwargs): ...
def bar_with_kwonly(self, *, k): ...
def bar_with_annotations(self, a: int): ...
2.2.19 async / await
async and await syntax was introduced from Python 3.5. They were designed to be used with an event loop. Some
other features such as the asynchronous generator were implemented in later versions.
A coroutine function (async def) are used to create a coroutine for an event loop. Python provides a built-in module,
asyncio, to write a concurrent code through async/await syntax. The following snippet shows a simple example of
using asyncio. The code must be run on Python 3.7 or above.
import asyncio
async def http_ok(r, w):
head = b"HTTP/1.1 200 OK\r\n"
head += b"Content-Type: text/html\r\n"
head += b"\r\n"
body = b"<html>"
body += b"<body><h1>Hello world!</h1></body>"
body += b"</html>"
(continues on next page)
2.2. From Scratch 31
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
_ = await r.read(1024)
w.write(head + body)
await w.drain()
w.close()
async def main():
server = await asyncio.start_server(
http_ok, "127.0.0.1", 8888
)
async with server:
await server.serve_forever()
asyncio.run(main())
2.2.20 Avoid exec and eval
The following snippet shows how to use the built-in function exec. Yet, using exec and eval are not recommended
because of some security issues and unreadable code for a human. Further reading can be found on Be careful with
exec and eval in Python and Eval really is dangerous
>>> py = '''
... def fib(n):
... a, b = 0, 1
... for _ in range(n):
... b, a = b + a, b
... return a
... print(fib(10))
... '''
>>> exec(py, globals(), locals())
55
2.3 Future
Future statements tell the interpreter to compile some semantics as the semantics which will be available in the future
Python version. In other words, Python uses from __future__ import feature to backport features from other
higher Python versions to the current interpreter. In Python 3, many features such as print_function are already
enabled, but we still leave these future statements for backward compatibility.
Future statements are NOT import statements. Future statements change how Python interprets the code. They MUST
be at the top of the file. Otherwise, Python interpreter will raise SyntaxError.
If you’re interested in future statements and want to acquire more explanation, further information can be found on PEP
236 - Back to the __future__
Table of Contents
• Future
– List All New Features
32 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
– Print Function
– Unicode
– Division
– Annotations
– BDFL Retirement
– Braces
2.3.1 List All New Features
__future__ is a Python module. We can use it to check what kind of future features can import to current Python
interpreter. The fun is import __future__ is NOT a future statement, it is a import statement.
>>> from pprint import pprint
>>> import __future__
>>> pprint(__future__.all_feature_names)
['nested_scopes',
'generators',
'division',
'absolute_import',
'with_statement',
'print_function',
'unicode_literals',
'barry_as_FLUFL',
'generator_stop',
'annotations']
Future statements not only change the behavior of the Python interpreter but also import __future__._Feature into
the current program.
>>> from __future__ import print_function
>>> print_function
_Feature((2, 6, 0, 'alpha', 2), (3, 0, 0, 'alpha', 0), 65536)
2.3.2 Print Function
Replacing print statement to print function is one of the most notorious decision in Python history. However, this
change brings some flexibilities to extend the ability of print. Further information can be found on PEP 3105.
>>> print "Hello World" # print is a statement
Hello World
>>> from __future__ import print_function
>>> print "Hello World"
File "<stdin>", line 1
print "Hello World"
^
SyntaxError: invalid syntax
>>> print("Hello World") # print become a function
Hello World
2.3. Future 33
python-cheatsheet Documentation, Release 0.1.0
2.3.3 Unicode
As print function, making text become Unicode is another infamous decision. Nevertheless, many modern program-
ming languages’ text is Unicode. This change compels us to decode texts early in order to prevent runtime error after
we run programs for a while. Further information can be found on PEP 3112.
>>> type("Guido") # string type is str in python2
<type 'str'>
>>> from __future__ import unicode_literals
>>> type("Guido") # string type become unicode
<type 'unicode'>
2.3.4 Division
Sometimes, it is counterintuitive when the division result is int or long. In this case, Python 3 enables the true division
by default. However, in Python 2, we have to backport division to the current interpreter. Further information can
be found on PEP 238.
>>> 1 / 2
0
>>> from __future__ import division
>>> 1 / 2 # return a float (classic division)
0.5
>>> 1 // 2 # return a int (floor division)
0
2.3.5 Annotations
Before Python 3.7, we cannot assign annotations in a class or a function if it is not available in the current scope. A
common situation is the definition of a container class.
class Tree(object):
def insert(self, tree: Tree): ...
Example
$ python3 foo.py
Traceback (most recent call last):
File "foo.py", line 1, in <module>
class Tree(object):
File "foo.py", line 3, in Tree
def insert(self, tree: Tree): ...
NameError: name 'Tree' is not defined
In this case, the definition of the class is not available yet. Python interpreter cannot parse the annotation during their
definition time. To solve this issue, Python uses string literals to replace the class.
class Tree(object):
def insert(self, tree: 'Tree'): ...
34 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
After version 3.7, Python introduces the future statement, annotations, to perform postponed evaluation. It will
become the default feature in Python 4. For further information please refer to PEP 563.
from __future__ import annotations
class Tree(object):
def insert(self, tree: Tree): ...
2.3.6 BDFL Retirement
New in Python 3.1
PEP 401 is just an Easter egg. This feature brings the current interpreter back to the past. It enables the diamond
operator <> in Python 3.
>>> 1 != 2
True
>>> from __future__ import barry_as_FLUFL
>>> 1 != 2
File "<stdin>", line 1
1 != 2
^
SyntaxError: with Barry as BDFL, use '<>' instead of '!='
>>> 1 <> 2
True
2.3.7 Braces
braces is an Easter egg. The source code can be found on future.c.
>>> from __future__ import braces
File "<stdin>", line 1
SyntaxError: not a chance
2.4 Unicode
The main goal of this cheat sheet is to collect some common snippets which are related to Unicode. In Python 3, strings
are represented by Unicode instead of bytes. Further information can be found on PEP 3100
ASCII code is the most well-known standard which defines numeric codes for characters. The numeric values only
define 128 characters originally, so ASCII only contains control codes, digits, lowercase letters, uppercase letters, etc.
However, it is not enough for us to represent characters such as accented characters, Chinese characters, or emoji existed
around the world. Therefore, Unicode was developed to solve this issue. It defines the code point to represent various
characters like ASCII but the number of characters is up to 1,111,998.
Table of Contents
• Unicode
2.4. Unicode 35
python-cheatsheet Documentation, Release 0.1.0
– String
– Characters
– Porting unicode(s, ‘utf-8’)
– Unicode Code Point
– Encoding
– Decoding
– Unicode Normalization
– Avoid UnicodeDecodeError
– Long String
2.4.1 String
In Python 2, strings are represented in bytes, not Unicode. Python provides different types of string such as Unicode
string, raw string, and so on. In this case, if we want to declare a Unicode string, we add u prefix for string literals.
>>> s = 'Café' # byte string
>>> s
'Caf\xc3\xa9'
>>> type(s)
<type 'str'>
>>> u = u'Café' # unicode string
>>> u
u'Caf\xe9'
>>> type(u)
<type 'unicode'>
In Python 3, strings are represented in Unicode. If we want to represent a byte string, we add the b prefix for string
literals. Note that the early Python versions (3.0-3.2) do not support the u prefix. In order to ease the pain to migrate
Unicode aware applications from Python 2, Python 3.3 once again supports the u prefix for string literals. Further
information can be found on PEP 414
>>> s = 'Café'
>>> type(s)
<class 'str'>
>>> s
'Café'
>>> s.encode('utf-8')
b'Caf\xc3\xa9'
>>> s.encode('utf-8').decode('utf-8')
'Café'
36 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.4.2 Characters
Python 2 takes all string characters as bytes. In this case, the length of strings may be not equivalent to the number of
characters. For example, the length of Café is 5, not 4 because é is encoded as a 2 bytes character.
>>> s= 'Café'
>>> print([_c for _c in s])
['C', 'a', 'f', '\xc3', '\xa9']
>>> len(s)
5
>>> s = u'Café'
>>> print([_c for _c in s])
[u'C', u'a', u'f', u'\xe9']
>>> len(s)
4
Python 3 takes all string characters as Unicode code point. The lenght of a string is always equivalent to the number
of characters.
>>> s = 'Café'
>>> print([_c for _c in s])
['C', 'a', 'f', 'é']
>>> len(s)
4
>>> bs = bytes(s, encoding='utf-8')
>>> print(bs)
b'Caf\xc3\xa9'
>>> len(bs)
5
2.4.3 Porting unicode(s, ‘utf-8’)
The unicode() built-in function was removed in Python 3 so what is the best way to convert the expression unicode(s,
'utf-8') so it works in both Python 2 and 3?
In Python 2:
>>> s = 'Café'
>>> unicode(s, 'utf-8')
u'Caf\xe9'
>>> s.decode('utf-8')
u'Caf\xe9'
>>> unicode(s, 'utf-8') == s.decode('utf-8')
True
In Python 3:
>>> s = 'Café'
>>> s.decode('utf-8')
AttributeError: 'str' object has no attribute 'decode'
So, the real answer is. . .
2.4. Unicode 37
python-cheatsheet Documentation, Release 0.1.0
2.4.4 Unicode Code Point
ord is a powerful built-in function to get a Unicode code point from a given character. Consequently, If we want to
check a Unicode code point of a character, we can use ord.
>>> s = u'Café'
>>> for _c in s: print('U+%04x' % ord(_c))
...
U+0043
U+0061
U+0066
U+00e9
>>> u = ''
>>> for _c in u: print('U+%04x' % ord(_c))
...
U+4e2d
U+6587
2.4.5 Encoding
A Unicode code point transfers to a byte string is called encoding.
>>> s = u'Café'
>>> type(s.encode('utf-8'))
<class 'bytes'>
2.4.6 Decoding
A byte string transfers to a Unicode code point is called decoding.
>>> s = bytes('Café', encoding='utf-8')
>>> s.decode('utf-8')
'Café'
2.4.7 Unicode Normalization
Some characters can be represented in two similar form. For example, the character, é can be written as e (Canonical
Decomposition) or é (Canonical Composition). In this case, we may acquire unexpected results when we are comparing
two strings even though they look alike. Therefore, we can normalize a Unicode form to solve the issue.
# python 3
>>> u1 = 'Café' # unicode string
>>> u2 = 'Cafe\u0301'
>>> u1, u2
('Café', 'Cafe')
>>> len(u1), len(u2)
(4, 5)
>>> u1 == u2
False
>>> u1.encode('utf-8') # get u1 byte string
(continues on next page)
38 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
b'Caf\xc3\xa9'
>>> u2.encode('utf-8') # get u2 byte string
b'Cafe\xcc\x81'
>>> from unicodedata import normalize
>>> s1 = normalize('NFC', u1) # get u1 NFC format
>>> s2 = normalize('NFC', u2) # get u2 NFC format
>>> s1 == s2
True
>>> s1.encode('utf-8'), s2.encode('utf-8')
(b'Caf\xc3\xa9', b'Caf\xc3\xa9')
>>> s1 = normalize('NFD', u1) # get u1 NFD format
>>> s2 = normalize('NFD', u2) # get u2 NFD format
>>> s1, s2
('Cafe', 'Cafe')
>>> s1 == s2
True
>>> s1.encode('utf-8'), s2.encode('utf-8')
(b'Cafe\xcc\x81', b'Cafe\xcc\x81')
2.4.8 Avoid UnicodeDecodeError
Python raises UnicodeDecodeError when byte strings cannot decode to Unicode code points. If we want to avoid this
exception, we can pass replace, backslashreplace, or ignore to errors argument in decode.
>>> u = b"\xff"
>>> u.decode('utf-8', 'strict')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start␣
˓→byte
>>> # use U+FFFD, REPLACEMENT CHARACTER
>>> u.decode('utf-8', "replace")
'\ufffd'
>>> # inserts a \xNN escape sequence
>>> u.decode('utf-8', "backslashreplace")
'\\xff'
>>> # leave the character out of the Unicode result
>>> u.decode('utf-8', "ignore")
''
2.4.9 Long String
The following snippet shows common ways to declare a multi-line string in Python.
# original long string
s = 'This is a very very very long python string'
# Single quote with an escaping backslash
s = "This is a very very very " \
"long python string"
(continues on next page)
2.4. Unicode 39
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
# Using brackets
s = (
"This is a very very very "
"long python string"
)
# Using ``+``
s = (
"This is a very very very " +
"long python string"
)
# Using triple-quote with an escaping backslash
s = '''This is a very very very \
long python string'''
2.5 List
The list is a common data structure which we use to store objects. Most of the time, programmers concern about
getting, setting, searching, filtering, and sorting. Furthermore, sometimes, we waltz ourself into common pitfalls of
the memory management. Thus, the main goal of this cheat sheet is to collect some common operations and pitfalls.
Table of Contents
• List
– From Scratch
– Initialize
– Copy
– Using slice
– List Comprehensions
– Unpacking
– Using enumerate
– Zip Lists
– Filter Items
– Stacks
– in Operation
– Accessing Items
– Delegating Iterations
– Sorting
– Sorted List
40 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
– New a List
– Circular Buffer
– Chunk
– Groupby
– Binary Search
– Lower Bound
– Upper Bound
– Lexicographically Order
– Trie
2.5.1 From Scratch
There are so many ways that we can manipulate lists in Python. Before we start to learn those versatile manipulations,
the following snippet shows the most common operations of lists.
>>> a = [1, 2, 3, 4, 5]
>>> # contains
>>> 2 in a
True
>>> # positive index
>>> a[0]
1
>>> # negative index
>>> a[-1]
5
>>> # slicing list[start:end:step]
>>> a[1:]
[2, 3, 4, 5]
>>> a[1:-1]
[2, 3, 4]
>>> a[1:-1:2]
[2, 4]
>>> # reverse
>>> a[::-1]
[5, 4, 3, 2, 1]
>>> a[:0:-1]
[5, 4, 3, 2]
>>> # set an item
>>> a[0] = 0
>>> a
[0, 2, 3, 4, 5]
>>> # append items to list
>>> a.append(6)
>>> a
[0, 2, 3, 4, 5, 6]
>>> a.extend([7, 8, 9])
>>> a
[0, 2, 3, 4, 5, 6, 7, 8, 9]
(continues on next page)
2.5. List 41
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
>>> # delete an item
>>> del a[-1]
>>> a
[0, 2, 3, 4, 5, 6, 7, 8]
>>> # list comprehension
>>> b = [x for x in range(3)]
>>> b
[0, 1, 2]
>>> # add two lists
>>> a + b
[0, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2]
2.5.2 Initialize
Generally speaking, we can create a list through * operator if the item in the list expression is an immutable object.
>>> a = [None] * 3
>>> a
[None, None, None]
>>> a[0] = "foo"
>>> a
['foo', None, None]
However, if the item in the list expression is a mutable object, the * operator will copy the reference of the item N times.
In order to avoid this pitfall, we should use a list comprehension to initialize a list.
>>> a = [[]] * 3
>>> b = [[] for _ in range(3)]
>>> a[0].append("Hello")
>>> a
[['Hello'], ['Hello'], ['Hello']]
>>> b[0].append("Python")
>>> b
[['Python'], [], []]
2.5.3 Copy
Assigning a list to a variable is a common pitfall. This assignment does not copy the list to the variable. The variable
only refers to the list and increase the reference count of the list.
import sys
>>> a = [1, 2, 3]
>>> sys.getrefcount(a)
2
>>> b = a
>>> sys.getrefcount(a)
3
>>> b[2] = 123456 # a[2] = 123456
>>> b
[1, 2, 123456]
(continues on next page)
42 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
>>> a
[1, 2, 123456]
There are two types of copy. The first one is called shallow copy (non-recursive copy) and the second one is called
deep copy (recursive copy). Most of the time, it is sufficient for us to copy a list by shallow copy. However, if a list is
nested, we have to use a deep copy.
>>> # shallow copy
>>> a = [1, 2]
>>> b = list(a)
>>> b[0] = 123
>>> a
[1, 2]
>>> b
[123, 2]
>>> a = [[1], [2]]
>>> b = list(a)
>>> b[0][0] = 123
>>> a
[[123], [2]]
>>> b
[[123], [2]]
>>> # deep copy
>>> import copy
>>> a = [[1], [2]]
>>> b = copy.deepcopy(a)
>>> b[0][0] = 123
>>> a
[[1], [2]]
>>> b
[[123], [2]]
2.5.4 Using slice
Sometimes, our data may concatenate as a large segment such as packets. In this case, we will represent the range of
data by using slice objects as explaining variables instead of using slicing expressions.
>>> icmp = (
... b"080062988e2100005bff49c20005767c"
... b"08090a0b0c0d0e0f1011121314151617"
... b"18191a1b1c1d1e1f2021222324252627"
... b"28292a2b2c2d2e2f3031323334353637"
... )
>>> head = slice(0, 32)
>>> data = slice(32, len(icmp))
>>> icmp[head]
b'080062988e2100005bff49c20005767c'
2.5. List 43
python-cheatsheet Documentation, Release 0.1.0
2.5.5 List Comprehensions
List comprehensions which was proposed in PEP 202 provides a graceful way to create a new list based on another
list, sequence, or some object which is iterable. In addition, we can use this expression to substitute map and filter
sometimes.
>>> [x for x in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [(lambda x: x**2)(i) for i in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> [x for x in range(10) if x > 5]
[6, 7, 8, 9]
>>> [x if x > 5 else 0 for x in range(10)]
[0, 0, 0, 0, 0, 0, 6, 7, 8, 9]
>>> [x + 1 if x < 5 else x + 2 if x > 5 else x + 5 for x in range(10)]
[1, 2, 3, 4, 5, 10, 8, 9, 10, 11]
>>> [(x, y) for x in range(3) for y in range(2)]
[(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
2.5.6 Unpacking
Sometimes, we want to unpack our list to variables in order to make our code become more readable. In this case, we
assign N elements to N variables as following example.
>>> arr = [1, 2, 3]
>>> a, b, c = arr
>>> a, b, c
(1, 2, 3)
Based on PEP 3132, we can use a single asterisk to unpack N elements to the number of variables which is less than N
in Python 3.
>>> arr = [1, 2, 3, 4, 5]
>>> a, b, *c, d = arr
>>> a, b, d
(1, 2, 5)
>>> c
[3, 4]
2.5.7 Using enumerate
enumerate is a built-in function. It helps us to acquire indexes (or a count) and elements at the same time without
using range(len(list)). Further information can be found on Looping Techniques.
>>> for i, v in enumerate(range(3)):
... print(i, v)
...
0 0
1 1
2 2
>>> for i, v in enumerate(range(3), 1): # start = 1
(continues on next page)
44 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
... print(i, v)
...
1 0
2 1
3 2
2.5.8 Zip Lists
zip enables us to iterate over items contained in multiple lists at a time. Iteration stops whenever one of the lists is
exhausted. As a result, the length of the iteration is the same as the shortest list. If this behavior is not desired, we can
use itertools.zip_longest in Python 3 or itertools.izip_longest in Python 2.
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> list(zip(a, b))
[(1, 4), (2, 5), (3, 6)]
>>> c = [1]
>>> list(zip(a, b, c))
[(1, 4, 1)]
>>> from itertools import zip_longest
>>> list(zip_longest(a, b, c))
[(1, 4, 1), (2, 5, None), (3, 6, None)]
2.5.9 Filter Items
filter is a built-in function to assist us to remove unnecessary items. In Python 2, filter returns a list. However, in
Python 3, filter returns an iterable object. Note that list comprehension or generator expression provides a more
concise way to remove items.
>>> [x for x in range(5) if x > 1]
[2, 3, 4]
>>> l = ['1', '2', 3, 'Hello', 4]
>>> f = lambda x: isinstance(x, int)
>>> filter(f, l)
<filter object at 0x10bee2198>
>>> list(filter(f, l))
[3, 4]
>>> list((i for i in l if f(i)))
[3, 4]
2.5. List 45
python-cheatsheet Documentation, Release 0.1.0
2.5.10 Stacks
There is no need for an additional data structure, stack, in Python because the list provides append and pop methods
which enable us use a list as a stack.
>>> stack = []
>>> stack.append(1)
>>> stack.append(2)
>>> stack.append(3)
>>> stack
[1, 2, 3]
>>> stack.pop()
3
>>> stack.pop()
2
>>> stack
[1]
2.5.11 in Operation
We can implement the __contains__ method to make a class do in operations. It is a common way for a programmer
to emulate a membership test operations for custom classes.
class Stack:
def __init__(self):
self.__list = []
def push(self, val):
self.__list.append(val)
def pop(self):
return self.__list.pop()
def __contains__(self, item):
return True if item in self.__list else False
stack = Stack()
stack.push(1)
print(1 in stack)
print(0 in stack)
Example
python stack.py
True
False
46 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.5.12 Accessing Items
Making custom classes perform get and set operations like lists is simple. We can implement a __getitem__ method
and a __setitem__ method to enable a class to retrieve and overwrite data by index. In addition, if we want to use the
function, len, to calculate the number of elements, we can implement a __len__ method.
class Stack:
def __init__(self):
self.__list = []
def push(self, val):
self.__list.append(val)
def pop(self):
return self.__list.pop()
def __repr__(self):
return "{}".format(self.__list)
def __len__(self):
return len(self.__list)
def __getitem__(self, idx):
return self.__list[idx]
def __setitem__(self, idx, val):
self.__list[idx] = val
stack = Stack()
stack.push(1)
stack.push(2)
print("stack:", stack)
stack[0] = 3
print("stack:", stack)
print("num items:", len(stack))
Example
$ python stack.py
stack: [1, 2]
stack: [3, 2]
num items: 2
2.5. List 47
python-cheatsheet Documentation, Release 0.1.0
2.5.13 Delegating Iterations
If a custom container class holds a list and we want iterations to work on the container, we can implement a __iter__
method to delegate iterations to the list. Note that the method, __iter__, should return an iterator object, so we cannot
return the list directly; otherwise, Python raises a TypeError.
class Stack:
def __init__(self):
self.__list = []
def push(self, val):
self.__list.append(val)
def pop(self):
return self.__list.pop()
def __iter__(self):
return iter(self.__list)
stack = Stack()
stack.push(1)
stack.push(2)
for s in stack:
print(s)
Example
$ python stack.py
1
2
2.5.14 Sorting
Python list provides a built-in list.sort method which sorts a list in-place without using extra memory. Moreover,
the return value of list.sort is None in order to avoid confusion with sorted and the function can only be used for
list.
>>> l = [5, 4, 3, 2, 1]
>>> l.sort()
>>> l
[1, 2, 3, 4, 5]
>>> l.sort(reverse=True)
>>> l
[5, 4, 3, 2, 1]
The sorted function does not modify any iterable object in-place. Instead, it returns a new sorted list. Using sorted
is safer than list.sort if some list’s elements are read-only or immutable. Besides, another difference between
list.sort and sorted is that sorted accepts any iterable object.
>>> l = [5, 4, 3, 2, 1]
>>> new = sorted(l)
>>> new
(continues on next page)
48 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
[1, 2, 3, 4, 5]
>>> l
[5, 4, 3, 2, 1]
>>> d = {3: 'andy', 2: 'david', 1: 'amy'}
>>> sorted(d) # sort iterable
[1, 2, 3]
To sort a list with its elements are tuples, using operator.itemgetter is helpful because it assigns a key function to
the sorted key parameter. Note that the key should be comparable; otherwise, it will raise a TypeError.
>>> from operator import itemgetter
>>> l = [('andy', 10), ('david', 8), ('amy', 3)]
>>> l.sort(key=itemgetter(1))
>>> l
[('amy', 3), ('david', 8), ('andy', 10)]
operator.itemgetter is useful because the function returns a getter method which can be applied to other objects
with a method __getitem__. For example, sorting a list with its elements are dictionary can be achieved by using
operator.itemgetter due to all elements have __getitem__.
>>> from pprint import pprint
>>> from operator import itemgetter
>>> l = [
... {'name': 'andy', 'age': 10},
... {'name': 'david', 'age': 8},
... {'name': 'amy', 'age': 3},
... ]
>>> l.sort(key=itemgetter('age'))
>>> pprint(l)
[{'age': 3, 'name': 'amy'},
{'age': 8, 'name': 'david'},
{'age': 10, 'name': 'andy'}]
If it is necessary to sort a list with its elements are neither comparable nor having __getitem__ method, assigning a
customized key function is feasible.
>>> class Node(object):
... def __init__(self, val):
... self.val = val
... def __repr__(self):
... return f"Node({self.val})"
...
>>> nodes = [Node(3), Node(2), Node(1)]
>>> nodes.sort(key=lambda x: x.val)
>>> nodes
[Node(1), Node(2), Node(3)]
>>> nodes.sort(key=lambda x: x.val, reverse=True)
>>> nodes
[Node(3), Node(2), Node(1)]
The above snippet can be simplified by using operator.attrgetter. The function returns an attribute getter based
on the attribute’s name. Note that the attribute should be comparable; otherwise, sorted or list.sort will raise
TypeError.
2.5. List 49
python-cheatsheet Documentation, Release 0.1.0
>>> from operator import attrgetter
>>> class Node(object):
... def __init__(self, val):
... self.val = val
... def __repr__(self):
... return f"Node({self.val})"
...
>>> nodes = [Node(3), Node(2), Node(1)]
>>> nodes.sort(key=attrgetter('val'))
>>> nodes
[Node(1), Node(2), Node(3)]
If an object has __lt__ method, it means that the object is comparable and sorted or list.sort is not necessary to
input a key function to its key parameter. A list or an iterable sequence can be sorted directly.
>>> class Node(object):
... def __init__(self, val):
... self.val = val
... def __repr__(self):
... return f"Node({self.val})"
... def __lt__(self, other):
... return self.val - other.val < 0
...
>>> nodes = [Node(3), Node(2), Node(1)]
>>> nodes.sort()
>>> nodes
[Node(1), Node(2), Node(3)]
If an object does not have __lt__ method, it is likely to patch the method after a declaration of the object’s class. In
other words, after the patching, the object becomes comparable.
>>> class Node(object):
... def __init__(self, val):
... self.val = val
... def __repr__(self):
... return f"Node({self.val})"
...
>>> Node.__lt__ = lambda s, o: s.val < o.val
>>> nodes = [Node(3), Node(2), Node(1)]
>>> nodes.sort()
>>> nodes
[Node(1), Node(2), Node(3)]
Note that sorted or list.sort in Python3 does not support cmp parameter which is an ONLY valid argument in
Python2. If it is necessary to use an old comparison function, e.g., some legacy code, functools.cmp_to_key is
useful since it converts a comparison function to a key function.
>>> from functools import cmp_to_key
>>> class Node(object):
... def __init__(self, val):
... self.val = val
... def __repr__(self):
... return f"Node({self.val})"
(continues on next page)
50 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
...
>>> nodes = [Node(3), Node(2), Node(1)]
>>> nodes.sort(key=cmp_to_key(lambda x,y: x.val - y.val))
>>> nodes
[Node(1), Node(2), Node(3)]
2.5.15 Sorted List
import bisect
class Foo(object):
def __init__(self, k):
self.k = k
def __eq__(self, rhs):
return self.k == rhs.k
def __ne__(self, rhs):
return self.k != rhs.k
def __lt__(self, rhs):
return self.k < rhs.k
def __gt__(self, rhs):
return self.k > rhs.k
def __le__(self, rhs):
return self.k <= rhs.k
def __ge__(self, rhs):
return self.k >= rhs.k
def __repr__(self):
return f"Foo({self.k})"
def __str__(self):
return self.__repr__()
foo = [Foo(1), Foo(3), Foo(2), Foo(0)]
bar = []
for x in foo:
bisect.insort(bar, x)
print(bar) # [Foo(0), Foo(1), Foo(2), Foo(3)]
2.5. List 51
python-cheatsheet Documentation, Release 0.1.0
2.5.16 New a List
# new a list with size = 3
>>> [0] * 3
[0, 0, 0]
# new a 2d list with size 3x3
>>> [[0] * 3 for _ in range(3)]
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
Note that we should avoid creating a multi-dimension list via the following snippet because all objects in the list point
to the same address.
>>> a = [[0] * 3] * 3
>>> a
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> a[1][1] = 2
>>> a
[[0, 2, 0], [0, 2, 0], [0, 2, 0]]
2.5.17 Circular Buffer
>>> from collections import deque
>>> d = deque(maxlen=8)
>>> for x in range(9):
... d.append(x)
...
>>> d
deque([1, 2, 3, 4, 5, 6, 7, 8], maxlen=8)
>>> from collections import deque
>>> def tail(path, n=10):
... with open(path) as f:
... return deque(f, n)
...
>>> tail("/etc/hosts")
2.5.18 Chunk
>>> def chunk(lst, n):
... for i in range(0, len(lst), n):
... yield lst[i:i+n]
...
>>> a = [1, 2, 3, 4, 5, 6, 7, 8]
>>> list(chunk(a, 3))
[[1, 2, 3], [4, 5, 6], [7, 8]]
52 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.5.19 Groupby
>>> import itertools
>>> s = "AAABBCCCCC"
>>> for k, v in itertools.groupby(s):
... print(k, list(v))
...
A ['A', 'A', 'A']
B ['B', 'B']
C ['C', 'C', 'C', 'C', 'C']
# group by key
>>> x = [('gp1', 'a'), ('gp2', 'b'), ('gp2', 'c')]
>>> for k, v in itertools.groupby(x, lambda x: x[0]):
... print(k, list(v))
...
gp1 [('gp1', 'a')]
gp2 [('gp2', 'b'), ('gp2', 'c')]
2.5.20 Binary Search
>>> def binary_search(arr, x, lo=0, hi=None):
... if not hi: hi = len(arr)
... pos = bisect_left(arr, x, lo, hi)
... return pos if pos != hi and arr[pos] == x else -1
...
>>> a = [1, 1, 1, 2, 3]
>>> binary_search(a, 1)
0
>>> binary_search(a, 2)
3
2.5.21 Lower Bound
>>> import bisect
>>> a = [1,2,3,3,4,5]
>>> bisect.bisect_left(a, 3)
2
>>> bisect.bisect_left(a, 3.5)
4
2.5. List 53
python-cheatsheet Documentation, Release 0.1.0
2.5.22 Upper Bound
>>> import bisect
>>> a = [1,2,3,3,4,5]
>>> bisect.bisect_right(a, 3)
4
>>> bisect.bisect_right(a, 3.5)
4
2.5.23 Lexicographically Order
# python compare lists lexicographically
>>> a = [(1,2), (1,1), (1,0), (2,1)]
>>> a.sort()
>>> a
[(1, 0), (1, 1), (1, 2), (2, 1)]
2.5.24 Trie
>>> from functools import reduce
>>> from collections import defaultdict
>>> Trie = lambda: defaultdict(Trie)
>>> prefixes = ['abc', 'de', 'g']
>>> trie = Trie()
>>> end = True
>>> for p in prefixes:
... reduce(dict.__getitem__, p, trie)[end] = p
...
# search prefix
>>> def find(trie, word):
... curr = trie
... for c in word:
... if c not in curr:
... return False
... curr = curr[c]
... return True
...
>>> find(trie, "abcdef")
False
>>> find(trie, "abc")
True
>>> find(trie, "ab")
True
# search word
>>> def find(trie, p):
(continues on next page)
54 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
... curr = trie
... for c in p:
... if c not in curr or True in curr:
... break
... curr = curr[c]
... return True if True in curr else False
...
>>> find(trie, "abcdef")
True
>>> find(trie, "abc")
True
>>> find(trie, "ab")
False
2.6 Set
Table of Contents
• Set
– Set comprehension
– Uniquify a List
– Union Two Sets
– Append Items to a Set
– Intersection Two Sets
– Common Items from Sets
– Contain
– Set Diff
– Symmetric diff
2.6.1 Set comprehension
>>> a = [1, 2, 5, 6, 6, 6, 7]
>>> s = {x for x in a}
>>> s
set([1, 2, 5, 6, 7])
>>> s = {x for x in a if x > 3}
>>> s
set([5, 6, 7])
>>> s = {x if x > 3 else -1 for x in a}
>>> s
set([6, 5, -1, 7])
2.6. Set 55
python-cheatsheet Documentation, Release 0.1.0
2.6.2 Uniquify a List
>>> a = [1, 2, 2, 2, 3, 4, 5, 5]
>>> a
[1, 2, 2, 2, 3, 4, 5, 5]
>>> ua = list(set(a))
>>> ua
[1, 2, 3, 4, 5]
2.6.3 Union Two Sets
>>> a = set([1, 2, 2, 2, 3])
>>> b = set([5, 5, 6, 6, 7])
>>> a | b
set([1, 2, 3, 5, 6, 7])
>>> # or
>>> a = [1, 2, 2, 2, 3]
>>> b = [5, 5, 6, 6, 7]
>>> set(a + b)
set([1, 2, 3, 5, 6, 7])
2.6.4 Append Items to a Set
>>> a = set([1, 2, 3, 3, 3])
>>> a.add(5)
>>> a
set([1, 2, 3, 5])
>>> # or
>>> a = set([1, 2, 3, 3, 3])
>>> a |= set([1, 2, 3, 4, 5, 6])
>>> a
set([1, 2, 3, 4, 5, 6])
2.6.5 Intersection Two Sets
>>> a = set([1, 2, 2, 2, 3])
>>> b = set([1, 5, 5, 6, 6, 7])
>>> a & b
set([1])
56 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.6.6 Common Items from Sets
>>> a = [1, 1, 2, 3]
>>> b = [1, 3, 5, 5, 6, 6]
>>> com = list(set(a) & set(b))
>>> com
[1, 3]
2.6.7 Contain
b contains a
>>> a = set([1, 2])
>>> b = set([1, 2, 5, 6])
>>> a <= b
True
a contains b
>>> a = set([1, 2, 5, 6])
>>> b = set([1, 5, 6])
>>> a >= b
True
2.6.8 Set Diff
>>> a = set([1, 2, 3])
>>> b = set([1, 5, 6, 7, 7])
>>> a - b
set([2, 3])
2.6.9 Symmetric diff
>>> a = set([1,2,3])
>>> b = set([1, 5, 6, 7, 7])
>>> a ^ b
set([2, 3, 5, 6, 7])
2.7 Dictionary
Table of Contents
• Dictionary
– Get All Keys
2.7. Dictionary 57
python-cheatsheet Documentation, Release 0.1.0
– Get Key and Value
– Find Same Keys
– Set a Default Value
– Update Dictionary
– Merge Two Dictionaries
– Emulating a Dictionary
– LRU Cache
2.7.1 Get All Keys
>>> a = {"1":1, "2":2, "3":3}
>>> b = {"2":2, "3":3, "4":4}
>>> a.keys()
['1', '3', '2']
2.7.2 Get Key and Value
>>> a = {"1":1, "2":2, "3":3}
>>> a.items()
2.7.3 Find Same Keys
>>> a = {"1":1, "2":2, "3":3}
>>> b = {"2":2, "3":3, "4":4}
>>> [_ for _ in a.keys() if _ in b.keys()]
['3', '2']
>>> # better way
>>> c = set(a).intersection(set(b))
>>> list(c)
['3', '2']
>>> # or
>>> [_ for _ in a if _ in b]
['3', '2']
[('1', 1), ('3', 3), ('2', 2)]
58 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.7.4 Set a Default Value
>>> # intuitive but not recommend
>>> d = {}
>>> key = "foo"
>>> if key not in d:
... d[key] = []
...
# using d.setdefault(key[, default])
>>> d = {}
>>> key = "foo"
>>> d.setdefault(key, [])
[]
>>> d[key] = 'bar'
>>> d
{'foo': 'bar'}
# using collections.defaultdict
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> d["key"]
[]
>>> d["foo"]
[]
>>> d["foo"].append("bar")
>>> d
defaultdict(<class 'list'>, {'key': [], 'foo': ['bar']})
dict.setdefault(key[, default]) returns its default value if key is not in the dictionary. However, if the key
exists in the dictionary, the function will return its value.
>>> d = {}
>>> d.setdefault("key", [])
[]
>>> d["key"] = "bar"
>>> d.setdefault("key", [])
'bar'
2.7.5 Update Dictionary
>>> a = {"1":1, "2":2, "3":3}
>>> b = {"2":2, "3":3, "4":4}
>>> a.update(b)
>>> a
{'1': 1, '3': 3, '2': 2, '4': 4}
2.7. Dictionary 59
python-cheatsheet Documentation, Release 0.1.0
2.7.6 Merge Two Dictionaries
Python 3.4 or lower
>>> a = {"x": 55, "y": 66}
>>> b = {"a": "foo", "b": "bar"}
>>> c = a.copy()
>>> c.update(b)
>>> c
{'y': 66, 'x': 55, 'b': 'bar', 'a': 'foo'}
Python 3.5 or above
>>> a = {"x": 55, "y": 66}
>>> b = {"a": "foo", "b": "bar"}
>>> c = {**a, **b}
>>> c
{'x': 55, 'y': 66, 'a': 'foo', 'b': 'bar'}
2.7.7 Emulating a Dictionary
>>> class EmuDict(object):
... def __init__(self, dict_):
... self._dict = dict_
... def __repr__(self):
... return "EmuDict: " + repr(self._dict)
... def __getitem__(self, key):
... return self._dict[key]
... def __setitem__(self, key, val):
... self._dict[key] = val
... def __delitem__(self, key):
... del self._dict[key]
... def __contains__(self, key):
... return key in self._dict
... def __iter__(self):
... return iter(self._dict.keys())
...
>>> _ = {"1":1, "2":2, "3":3}
>>> emud = EmuDict(_)
>>> emud # __repr__
EmuDict: {'1': 1, '2': 2, '3': 3}
>>> emud['1'] # __getitem__
1
>>> emud['5'] = 5 # __setitem__
>>> emud
EmuDict: {'1': 1, '2': 2, '3': 3, '5': 5}
>>> del emud['2'] # __delitem__
>>> emud
EmuDict: {'1': 1, '3': 3, '5': 5}
>>> for _ in emud:
... print(emud[_], end=' ') # __iter__
... else:
(continues on next page)
60 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
... print()
...
1 3 5
>>> '1' in emud # __contains__
True
2.7.8 LRU Cache
from collections import OrderedDict
class LRU(object):
def __init__(self, maxsize=128):
self._maxsize = maxsize
self._cache = OrderedDict()
def get(self, k):
if k not in self._cache:
return None
self._cache.move_to_end(k)
return self._cache[k]
def put(self, k, v):
if k in self._cache:
self._cache.move_to_end(k)
self._cache[k] = v
if len(self._cache) > self._maxsize:
self._cache.popitem(last=False)
def __str__(self):
return str(self._cache)
def __repr__(self):
return self.__str__()
Note that dictionaries preserve insertion order from Python 3.7. Moreover, updating a key does not affect the order.
Therefore, a dictionary can also simulate an LRU cache, which is similar to using an OrderedDict.
class LRU(object):
def __init__(self, maxsize=128):
self._maxsize = maxsize
self._cache = {}
def get(self, k):
if k not in self._cache:
return None
self.move_to_end(k)
return self._cache[k]
(continues on next page)
2.7. Dictionary 61
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
def put(self, k, v):
if k in self._cache:
self.move_to_end(k)
self._cache[k] = v
if len(self._cache) > self._maxsize:
self.pop()
def pop(self):
it = iter(self._cache.keys())
del self._cache[next(it)]
def move_to_end(self, k):
if k not in self._cache:
return
v = self._cache[k]
del self._cache[k]
self._cache[k] = v
def __str__(self):
return str(self._cache)
def __repr__(self):
return self.__str__()
2.8 Heap
Table of Contents
• Heap
– Heap Sort
– Priority Queue
2.8.1 Heap Sort
>>> import heapq
>>> a = [5, 1, 3, 2, 6]
>>> h = []
>>> for x in a:
... heapq.heappush(h, x)
...
>>> x = [heapq.heappop(h) for _ in range(len(a))]
>>> x
[1, 2, 3, 5, 6]
62 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.8.2 Priority Queue
import heapq
h = []
heapq.heappush(h, (1, "1")) # (priority, value)
heapq.heappush(h, (5, "5"))
heapq.heappush(h, (3, "3"))
heapq.heappush(h, (2, "2"))
x = [heapq.heappop(h) for _ in range(len(h))]
print(x)
import heapq
class Num(object):
def __init__(self, n):
self._n = n
def __lt__(self, other):
return self._n < other._n
def __repr__(self):
return self.__str__()
def __str__(self):
return f"Num({self._n})"
h = []
heapq.heappush(h, Num(5))
heapq.heappush(h, Num(2))
heapq.heappush(h, Num(1))
x = [heapq.heappop(h) for _ in range(len(h))]
print(x)
# output: [Num(1), Num(2), Num(5)]
2.9 Function
A function can help programmers to wrap their logic into a task for avoiding duplicate code. In Python, the definition
of a function is so versatile that we can use many features such as decorator, annotation, docstrings, default arguments
and so on to define a function. In this cheat sheet, it collects many ways to define a function and demystifies some
enigmatic syntax in functions.
Table of Contents
• Function
– Document Functions
– Default Arguments
– Option Arguments
2.9. Function 63
python-cheatsheet Documentation, Release 0.1.0
– Unpack Arguments
– Keyword-Only Arguments
– Annotations
– Callable
– Get Function Name
– Lambda
– Generator
– Decorator
– Decorator with Arguments
– Cache
2.9.1 Document Functions
Documentation provides programmers hints about how a function is supposed to be used. A docstring gives an expedi-
ent way to write a readable document of functions. PEP 257 defines some conventions of docstrings. In order to avoid
violating conventions, there are several tools such as doctest, or pydocstyle can help us check the format of docstrings.
>>> def example():
... """This is an example function."""
... print("Example function")
...
>>> example.__doc__
'This is an example function.'
>>> help(example)
2.9.2 Default Arguments
Defining a function where the arguments are optional and have a default value is quite simple in Python. We can just
assign values in the definition and make sure the default arguments appear in the end.
>>> def add(a, b=0):
... return a + b
...
>>> add(1)
1
>>> add(1, 2)
3
>>> add(1, b=2)
3
64 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.9.3 Option Arguments
>>> def example(a, b=None, *args, **kwargs):
... print(a, b)
... print(args)
... print(kwargs)
...
>>> example(1, "var", 2, 3, word="hello")
1 var
(2, 3)
{'word': 'hello'}
2.9.4 Unpack Arguments
>>> def foo(a, b, c='BAZ'):
... print(a, b, c)
...
>>> foo(*("FOO", "BAR"), **{"c": "baz"})
FOO BAR baz
2.9.5 Keyword-Only Arguments
New in Python 3.0
>>> def f(a, b, *, kw):
... print(a, b, kw)
...
>>> f(1, 2, kw=3)
1 2 3
>>> f(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 2 positional arguments but 3 were given
2.9.6 Annotations
New in Python 3.0
Annotations can be a useful way to give programmers hints about types of arguments. The specification of this feature
is on PEP 3107. Python 3.5 introduced typing module to extend the concept of type hints. Moreover, from version
3.6, Python started to offer a general way to define a variable with an annotation. Further information can be found on
PEP 483, PEP 484, and PEP 526.
>>> def fib(n: int) -> int:
... a, b = 0, 1
... for _ in range(n):
... b, a = a + b, b
... return a
...
(continues on next page)
2.9. Function 65
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
>>> fib(10)
55
>>> fib.__annotations__
{'n': <class 'int'>, 'return': <class 'int'>}
2.9.7 Callable
In some cases such as passing a callback function, we need to check whether an object is callable or not. The built-in
function, callable, assist us to avoid raising a TypeError if the object is not callable.
>>> a = 10
>>> def fun():
... print("I am callable")
...
>>> callable(a)
False
>>> callable(fun)
True
2.9.8 Get Function Name
>>> def example_function():
... pass
...
>>> example_function.__name__
'example_function'
2.9.9 Lambda
Sometimes, we don’t want to use the def statement to define a short callback function. We can use a lambda expression
as a shortcut to define an anonymous or an inline function instead. However, only one single expression can be specified
in lambda. That is, no other features such as multi-line statements, conditions, or exception handling can be contained.
>>> fn = lambda x: x**2
>>> fn(3)
9
>>> (lambda x: x**2)(3)
9
>>> (lambda x: [x*_ for _ in range(5)])(2)
[0, 2, 4, 6, 8]
>>> (lambda x: x if x>3 else 3)(5)
5
66 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.9.10 Generator
>>> def fib(n):
... a, b = 0, 1
... for _ in range(n):
... yield a
... b, a = a + b, b
...
>>> [f for f in fib(10)]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
2.9.11 Decorator
New in Python 2.4
• PEP 318 - Decorators for Functions and Methods
>>> from functools import wraps
>>> def decorator(func):
... @wraps(func)
... def wrapper(*args, **kwargs):
... print("Before calling {}.".format(func.__name__))
... ret = func(*args, **kwargs)
... print("After calling {}.".format(func.__name__))
... return ret
... return wrapper
...
>>> @decorator
... def example():
... print("Inside example function.")
...
>>> example()
Before calling example.
Inside example function.
After calling example.
Equals to
... def example():
... print("Inside example function.")
...
>>> example = decorator(example)
>>> example()
Before calling example.
Inside example function.
After calling example.
2.9. Function 67
python-cheatsheet Documentation, Release 0.1.0
2.9.12 Decorator with Arguments
>>> from functools import wraps
>>> def decorator_with_argument(val):
... def decorator(func):
... @wraps(func)
... def wrapper(*args, **kwargs):
... print("Val is {0}".format(val))
... return func(*args, **kwargs)
... return wrapper
... return decorator
...
>>> @decorator_with_argument(10)
... def example():
... print("This is example function.")
...
>>> example()
Val is 10
This is example function.
Equals to
>>> def example():
... print("This is example function.")
...
>>> example = decorator_with_argument(10)(example)
>>> example()
Val is 10
This is example function.
2.9.13 Cache
New in Python 3.2
Without Cache
>>> import time
>>> def fib(n):
... if n < 2:
... return n
... return fib(n - 1) + fib(n - 2)
...
>>> s = time.time(); _ = fib(32); e = time.time(); e - s
1.1562161445617676
With Cache (dynamic programming)
>>> from functools import lru_cache
>>> @lru_cache(maxsize=None)
... def fib(n):
... if n < 2:
... return n
... return fib(n - 1) + fib(n - 2)
(continues on next page)
68 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
...
>>> s = time.time(); _ = fib(32); e = time.time(); e - s
2.9087066650390625e-05
>>> fib.cache_info()
CacheInfo(hits=30, misses=33, maxsize=None, currsize=33)
2.10 Classes and Objects
Table of Contents
• Classes and Objects
– List Attributes
– Get Instance Type
– Declare a Class
– Has / Get / Set Attributes
– Check Inheritance
– Get Class Name
– New and Init
– The Diamond Problem
– Representation of a Class
– Callable Object
– Context Manager
– Using contextlib
– Property
– Computed Attributes
– Descriptor
– Singleton Decorator
– Static and Class Methond
– Abstract Method
– Using slot to Save Memory
– Common Magic
2.10. Classes and Objects 69
python-cheatsheet Documentation, Release 0.1.0
2.10.1 List Attributes
>>> dir(list) # check all attr of list
['__add__', '__class__', ...]
2.10.2 Get Instance Type
>>> ex = 10
>>> isinstance(ex, int)
True
2.10.3 Declare a Class
>>> def fib(self, n):
... if n <= 2:
... return 1
... return fib(self, n-1) + fib(self, n-2)
...
>>> Fib = type('Fib', (object,), {'val': 10,
... 'fib': fib})
>>> f = Fib()
>>> f.val
10
>>> f.fib(f.val)
55
Equals to
>>> class Fib(object):
... val = 10
... def fib(self, n):
... if n <=2:
... return 1
... return self.fib(n-1)+self.fib(n-2)
...
>>> f = Fib()
>>> f.val
10
>>> f.fib(f.val)
55
70 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.10.4 Has / Get / Set Attributes
>>> class Example(object):
... def __init__(self):
... self.name = "ex"
... def printex(self):
... print("This is an example")
...
>>> ex = Example()
>>> hasattr(ex,"name")
True
>>> hasattr(ex,"printex")
True
>>> hasattr(ex,"print")
False
>>> getattr(ex,'name')
'ex'
>>> setattr(ex,'name','example')
>>> ex.name
'example'
2.10.5 Check Inheritance
>>> class Example(object):
... def __init__(self):
... self.name = "ex"
... def printex(self):
... print("This is an Example")
...
>>> issubclass(Example, object)
True
2.10.6 Get Class Name
>>> class ExampleClass(object):
... pass
...
>>> ex = ExampleClass()
>>> ex.__class__.__name__
'ExampleClass'
2.10. Classes and Objects 71
python-cheatsheet Documentation, Release 0.1.0
2.10.7 New and Init
__init__ will be invoked
>>> class ClassA(object):
... def __new__(cls, arg):
... print('__new__ ' + arg)
... return object.__new__(cls, arg)
... def __init__(self, arg):
... print('__init__ ' + arg)
...
>>> o = ClassA("Hello")
__new__ Hello
__init__ Hello
__init__ won’t be invoked
>>> class ClassB(object):
... def __new__(cls, arg):
... print('__new__ ' + arg)
... return object
... def __init__(self, arg):
... print('__init__ ' + arg)
...
>>> o = ClassB("Hello")
__new__ Hello
2.10.8 The Diamond Problem
The problem of multiple inheritance in searching a method
>>> def foo_a(self):
... print("This is ClsA")
...
>>> def foo_b(self):
... print("This is ClsB")
...
>>> def foo_c(self):
... print("This is ClsC")
...
>>> class Type(type):
... def __repr__(cls):
... return cls.__name__
...
>>> ClsA = Type("ClsA", (object,), {'foo': foo_a})
>>> ClsB = Type("ClsB", (ClsA,), {'foo': foo_b})
>>> ClsC = Type("ClsC", (ClsA,), {'foo': foo_c})
>>> ClsD = Type("ClsD", (ClsB, ClsC), {})
>>> ClsD.mro()
[ClsD, ClsB, ClsC, ClsA, <type 'object'>]
>>> ClsD().foo()
This is ClsB
72 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.10.9 Representation of a Class
>>> class Example(object):
... def __str__(self):
... return "Example __str__"
... def __repr__(self):
... return "Example __repr__"
...
>>> print(str(Example()))
Example __str__
>>> Example()
Example __repr__
2.10.10 Callable Object
>>> class CallableObject(object):
... def example(self, *args, **kwargs):
... print("I am callable!")
... def __call__(self, *args, **kwargs):
... self.example(*args, **kwargs)
...
>>> ex = CallableObject()
>>> ex()
I am callable!
2.10.11 Context Manager
# replace try: ... finally: ...
# see: PEP343
# common use in open and close
import socket
class Socket(object):
def __init__(self, host, port):
self.host = host
self.port = port
def __enter__(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((self.host,self.port))
sock.listen(5)
self.sock = sock
return self.sock
def __exit__(self,*exc_info):
if exc_info[0] is not None:
import traceback
traceback.print_exception(*exc_info)
self.sock.close()
(continues on next page)
2.10. Classes and Objects 73
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
if __name__=="__main__":
host = 'localhost'
port = 5566
with Socket(host, port) as s:
while True:
conn, addr = s.accept()
msg = conn.recv(1024)
print(msg)
conn.send(msg)
conn.close()
2.10.12 Using contextlib
from contextlib import contextmanager
@contextmanager
def opening(filename, mode='r'):
f = open(filename, mode)
try:
yield f
finally:
f.close()
with opening('example.txt') as fd:
fd.read()
2.10.13 Property
>>> class Example(object):
... def __init__(self, value):
... self._val = value
... @property
... def val(self):
... return self._val
... @val.setter
... def val(self, value):
... if not isinstance(value, int):
... raise TypeError("Expected int")
... self._val = value
... @val.deleter
... def val(self):
... del self._val
...
>>> ex = Example(123)
>>> ex.val = "str"
Traceback (most recent call last):
File "", line 1, in
File "test.py", line 12, in val
(continues on next page)
74 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
raise TypeError("Expected int")
TypeError: Expected int
Equals to
>>> class Example(object):
... def __init__(self, value):
... self._val = value
...
... def _val_getter(self):
... return self._val
...
... def _val_setter(self, value):
... if not isinstance(value, int):
... raise TypeError("Expected int")
... self._val = value
...
... def _val_deleter(self):
... del self._val
...
... val = property(fget=_val_getter, fset=_val_setter, fdel=_val_deleter, doc=None)
...
2.10.14 Computed Attributes
@property computes a value of a attribute only when we need. Not store in memory previously.
>>> class Example(object):
... @property
... def square3(self):
... return 2**3
...
>>> ex = Example()
>>> ex.square3
8
2.10.15 Descriptor
>>> class Integer(object):
... def __init__(self, name):
... self._name = name
... def __get__(self, inst, cls):
... if inst is None:
... return self
... else:
... return inst.__dict__[self._name]
... def __set__(self, inst, value):
... if not isinstance(value, int):
... raise TypeError("Expected int")
(continues on next page)
2.10. Classes and Objects 75
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
... inst.__dict__[self._name] = value
... def __delete__(self,inst):
... del inst.__dict__[self._name]
...
>>> class Example(object):
... x = Integer('x')
... def __init__(self, val):
... self.x = val
...
>>> ex1 = Example(1)
>>> ex1.x
1
>>> ex2 = Example("str")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __init__
File "<stdin>", line 11, in __set__
TypeError: Expected an int
>>> ex3 = Example(3)
>>> hasattr(ex3, 'x')
True
>>> del ex3.x
>>> hasattr(ex3, 'x')
False
2.10.16 Singleton Decorator
Singleton is a design pattern that restricts the creation of instances of a class so that it only creates one instance of the
class that implements it.
#!/usr/bin/env python3
"""Singleton decorator class."""
class Singleton(object):
def __init__(self, cls):
self.__cls = cls
self.__obj = None
def __call__(self, *args, **kwargs):
if not self.__obj:
self.__obj = self.__cls(*args, **kwargs)
return self.__obj
if __name__ == "__main__":
# Testing ...
@Singleton
class Test(object):
def __init__(self, text):
(continues on next page)
76 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
self.text = text
a = Test("Hello")
b = Test("World")
print("id(a):", id(a), "id(b):", id(b), "Diff:", id(a)-id(b))
2.10.17 Static and Class Methond
@classmethod is bound to a class. @staticmethod is similar to a python function but define in a class.
>>> class example(object):
... @classmethod
... def clsmethod(cls):
... print("I am classmethod")
... @staticmethod
... def stmethod():
... print("I am staticmethod")
... def instmethod(self):
... print("I am instancemethod")
...
>>> ex = example()
>>> ex.clsmethod()
I am classmethod
>>> ex.stmethod()
I am staticmethod
>>> ex.instmethod()
I am instancemethod
>>> example.clsmethod()
I am classmethod
>>> example.stmethod()
I am staticmethod
>>> example.instmethod()
Traceback (most recent call last):
File "", line 1, in
TypeError: unbound method instmethod() ...
2.10.18 Abstract Method
abc is used to define methods but not implement
>>> from abc import ABCMeta, abstractmethod
>>> class base(object):
... __metaclass__ = ABCMeta
... @abstractmethod
... def absmethod(self):
... """ Abstract method """
...
>>> class example(base):
... def absmethod(self):
(continues on next page)
2.10. Classes and Objects 77
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
... print("abstract")
...
>>> ex = example()
>>> ex.absmethod()
abstract
Another common way is to raise NotImplementedError
>>> class base(object):
... def absmethod(self):
... raise NotImplementedError
...
>>> class example(base):
... def absmethod(self):
... print("abstract")
...
>>> ex = example()
>>> ex.absmethod()
abstract
2.10.19 Using slot to Save Memory
#!/usr/bin/env python3
import resource
import platform
import functools
def profile_mem(func):
@functools.wraps(func)
def wrapper(*a, **k):
s = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
ret = func(*a, **k)
e = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
uname = platform.system()
if uname == "Linux":
print(f"mem usage: {e - s} kByte")
elif uname == "Darwin":
print(f"mem usage: {e - s} Byte")
else:
raise Exception("not support")
return ret
return wrapper
class S(object):
__slots__ = ['attr1', 'attr2', 'attr3']
(continues on next page)
78 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
def __init__(self):
self.attr1 = "Foo"
self.attr2 = "Bar"
self.attr3 = "Baz"
class D(object):
def __init__(self):
self.attr1 = "Foo"
self.attr2 = "Bar"
self.attr3 = "Baz"
@profile_mem
def alloc(cls):
_ = [cls() for _ in range(1000000)]
alloc(S)
alloc(D)
output:
$ python3.6 s.py
mem usage: 70922240 Byte
mem usage: 100659200 Byte
2.10.20 Common Magic
# see python document: data model
# For command class
__main__
__name__
__file__
__module__
__all__
__dict__
__class__
__doc__
__init__(self, [...)
__str__(self)
__repr__(self)
__del__(self)
# For Descriptor
__get__(self, instance, owner)
__set__(self, instance, value)
__delete__(self, instance)
(continues on next page)
2.10. Classes and Objects 79
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
# For Context Manager
__enter__(self)
__exit__(self, exc_ty, exc_val, tb)
# Emulating container types
__len__(self)
__getitem__(self, key)
__setitem__(self, key, value)
__delitem__(self, key)
__iter__(self)
__contains__(self, value)
# Controlling Attribute Access
__getattr__(self, name)
__setattr__(self, name, value)
__delattr__(self, name)
__getattribute__(self, name)
# Callable object
__call__(self, [args...])
# Compare related
__cmp__(self, other)
__eq__(self, other)
__ne__(self, other)
__lt__(self, other)
__gt__(self, other)
__le__(self, other)
__ge__(self, other)
# arithmetical operation related
__add__(self, other)
__sub__(self, other)
__mul__(self, other)
__div__(self, other)
__mod__(self, other)
__and__(self, other)
__or__(self, other)
__xor__(self, other)
2.11 Generator
Table of Contents
• Generator
– Glossary of Generator
– Produce value via generator
80 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
– Unpacking Generators
– Implement Iterable object via generator
– Send message to generator
– yield from expression
– yield (from) EXPR return RES
– Generate sequences
– What RES = yield from EXP actually do?
– for _ in gen() simulate yield from
– Check generator type
– Check Generator State
– Simple compiler
– Context manager and generator
– What @contextmanager actually doing?
– profile code block
– yield from and __iter__
– yield from == await expression
– Closure in Python - using generator
– Implement a simple scheduler
– Simple round-robin with blocking
– simple round-robin with blocking and non-blocking
– Asynchronous Generators
– Asynchronous generators can have try..finally blocks
– send value and throw exception into async generator
– Simple async round-robin
– Async generator get better performance than async iterator
– Asynchronous Comprehensions
2.11.1 Glossary of Generator
# generator function
>>> def gen_func():
... yield 5566
...
>>> gen_func
<function gen_func at 0x1019273a>
# generator
(continues on next page)
2.11. Generator 81
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
#
# calling the generator function returns a generator
>>> g = gen_func()
>>> g
<generator object gen_func at 0x101238fd>
>>> next(g)
5566
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
# generator expression
#
# generator expression evaluating directly to a generator
>>> g = (x for x in range(2))
>>> g
<generator object <genexpr> at 0x10a9c191>
>>> next(g)
0
>>> next(g)
1
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
2.11.2 Produce value via generator
>>> from __future__ import print_function
>>> def prime(n):
... p = 2
... while n > 0:
... for x in range(2, p):
... if p % x == 0:
... break
... else:
... yield p
... n -= 1
... p += 1
...
>>> p = prime(3)
>>> next(p)
2
>>> next(p)
3
>>> next(p)
5
(continues on next page)
82 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
>>> next(p)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> for x in prime(5):
... print(x, end=" ")
...
2 3 5 7 11 >>>
2.11.3 Unpacking Generators
# PEP 448
# unpacking inside a list
>>> g1 = (x for x in range(3))
>>> g2 = (x**2 for x in range(2))
>>> [1, *g1, 2, *g2]
[1, 0, 1, 2, 2, 0, 1]
>>> # equal to
>>> g1 = (x for x in range(3))
>>> g2 = (x**2 for x in range(2))
>>> [1] + list(g1) + [2] + list(g2)
[1, 0, 1, 2, 2, 0, 1]
# unpacking inside a set
>>> g = (x for x in [5, 5, 6, 6])
>>> {*g}
{5, 6}
# unpacking to variables
>>> g = (x for x in range(3))
>>> a, b, c = g
>>> print(a, b, c)
0 1 2
>>> g = (x for x in range(6))
>>> a, b, *c, d = g
>>> print(a, b, d)
0 1 5
>>> print(c)
[2, 3, 4]
# unpacking inside a function
>>> print(*(x for x in range(3)))
0 1 2
2.11. Generator 83
python-cheatsheet Documentation, Release 0.1.0
2.11.4 Implement Iterable object via generator
>>> from __future__ import print_function
>>> class Count(object):
... def __init__(self, n):
... self._n = n
... def __iter__(self):
... n = self._n
... while n > 0:
... yield n
... n -= 1
... def __reversed__(self):
... n = 1
... while n <= self._n:
... yield n
... n += 1
...
>>> for x in Count(5):
... print(x, end=" ")
...
5 4 3 2 1 >>>
>>> for x in reversed(Count(5)):
... print(x, end=" ")
...
1 2 3 4 5 >>>
2.11.5 Send message to generator
>>> def spam():
... msg = yield
... print("Message:", msg)
...
>>> try:
... g = spam()
... # start generator
... next(g)
... # send message to generator
... g.send("Hello World!")
... except StopIteration:
... pass
...
Message: Hello World!
84 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.11.6 yield from expression
# delegating gen do nothing(pipe)
>>> def subgen():
... try:
... yield 9527
... except ValueError:
... print("get value error")
...
>>> def delegating_gen():
... yield from subgen()
...
>>> g = delegating_gen()
>>> try:
... next(g)
... g.throw(ValueError)
... except StopIteration:
... print("gen stop")
...
9527
get value error
gen stop
# yield from + yield from
>>> import inspect
>>> def subgen():
... yield from range(5)
...
>>> def delegating_gen():
... yield from subgen()
...
>>> g = delegating_gen()
>>> inspect.getgeneratorstate(g)
'GEN_CREATED'
>>> next(g)
0
>>> inspect.getgeneratorstate(g)
'GEN_SUSPENDED'
>>> g.close()
>>> inspect.getgeneratorstate(g)
'GEN_CLOSED'
2.11.7 yield (from) EXPR return RES
>>> def average():
... total = .0
... count = 0
... avg = None
... while True:
... val = yield
... if not val:
(continues on next page)
2.11. Generator 85
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
... break
... total += val
... count += 1
... avg = total / count
... return avg
...
>>> g = average()
>>> next(g) # start gen
>>> g.send(3)
>>> g.send(5)
>>> try:
... g.send(None)
... except StopIteration as e:
... ret = e.value
...
>>> ret
4.0
# yield from EXP return RES
>>> def subgen():
... yield 9527
...
>>> def delegating_gen():
... yield from subgen()
... return 5566
...
>>> try:
... g = delegating_gen()
... next(g)
... next(g)
... except StopIteration as _e:
... print(_e.value)
...
9527
5566
2.11.8 Generate sequences
# get a list via generator
>>> def chain():
... for x in 'ab':
... yield x
... for x in range(3):
... yield x
...
>>> a = list(chain())
>>> a
['a', 'b', 0, 1, 2]
(continues on next page)
86 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
# equivalent to
>>> def chain():
... yield from 'ab'
... yield from range(3)
...
>>> a = list(chain())
>>> a
['a', 'b', 0, 1, 2]
2.11.9 What RES = yield from EXP actually do?
# ref: pep380
>>> def subgen():
... for x in range(3):
... yield x
...
>>> EXP = subgen()
>>> def delegating_gen():
... _i = iter(EXP)
... try:
... _y = next(_i)
... except StopIteration as _e:
... RES = _e.value
... else:
... while True:
... _s = yield _y
... try:
... _y = _i.send(_s)
... except StopIteration as _e:
... RES = _e.value
... break
...
>>> g = delegating_gen()
>>> next(g)
0
>>> next(g)
1
>>> next(g)
2
# equivalent to
>>> EXP = subgen()
>>> def delegating_gen():
... RES = yield from EXP
...
>>> g = delegating_gen()
>>> next(g)
0
>>> next(g)
1
2.11. Generator 87
python-cheatsheet Documentation, Release 0.1.0
2.11.10 for _ in gen() simulate yield from
>>> def subgen(n):
... for x in range(n): yield x
...
>>> def gen(n):
... yield from subgen(n)
...
>>> g = gen(3)
>>> next(g)
0
>>> next(g)
1
# equal to
>>> def gen(n):
... for x in subgen(n): yield x
...
>>> g = gen(3)
>>> next(g)
0
>>> next(g)
1
2.11.11 Check generator type
>>> from types import GeneratorType
>>> def gen_func():
... yield 5566
...
>>> g = gen_func()
>>> isinstance(g, GeneratorType)
True
>>> isinstance(123, GeneratorType)
False
2.11.12 Check Generator State
>>> import inspect
>>> def gen_func():
... yield 9527
...
>>> g = gen_func()
>>> inspect.getgeneratorstate(g)
'GEN_CREATED'
>>> next(g)
9527
>>> inspect.getgeneratorstate(g)
'GEN_SUSPENDED'
(continues on next page)
88 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
>>> g.close()
>>> inspect.getgeneratorstate(g)
'GEN_CLOSED'
2.11.13 Simple compiler
# David Beazley - Generators: The Final Frontier
import re
import types
from collections import namedtuple
tokens = [
r'(?P<NUMBER>\d+)',
r'(?P<PLUS>\+)',
r'(?P<MINUS>-)',
r'(?P<TIMES>\*)',
r'(?P<DIVIDE>/)',
r'(?P<WS>\s+)']
Token = namedtuple('Token', ['type', 'value'])
lex = re.compile('|'.join(tokens))
def tokenize(text):
scan = lex.scanner(text)
gen = (Token(m.lastgroup, m.group())
for m in iter(scan.match, None) if m.lastgroup != 'WS')
return gen
class Node:
_fields = []
def __init__(self, *args):
for attr, value in zip(self._fields, args):
setattr(self, attr, value)
class Number(Node):
_fields = ['value']
class BinOp(Node):
_fields = ['op', 'left', 'right']
def parse(toks):
lookahead, current = next(toks, None), None
def accept(*toktypes):
nonlocal lookahead, current
if lookahead and lookahead.type in toktypes:
current, lookahead = lookahead, next(toks, None)
return True
(continues on next page)
2.11. Generator 89
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
def expr():
left = term()
while accept('PLUS', 'MINUS'):
left = BinOp(current.value, left)
left.right = term()
return left
def term():
left = factor()
while accept('TIMES', 'DIVIDE'):
left = BinOp(current.value, left)
left.right = factor()
return left
def factor():
if accept('NUMBER'):
return Number(int(current.value))
else:
raise SyntaxError()
return expr()
class NodeVisitor:
def visit(self, node):
stack = [self.genvisit(node)]
ret = None
while stack:
try:
node = stack[-1].send(ret)
stack.append(self.genvisit(node))
ret = None
except StopIteration as e:
stack.pop()
ret = e.value
return ret
def genvisit(self, node):
ret = getattr(self, 'visit_' + type(node).__name__)(node)
if isinstance(ret, types.GeneratorType):
ret = yield from ret
return ret
class Evaluator(NodeVisitor):
def visit_Number(self, node):
return node.value
def visit_BinOp(self, node):
leftval = yield node.left
rightval = yield node.right
if node.op == '+':
return leftval + rightval
(continues on next page)
90 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
elif node.op == '-':
return leftval - rightval
elif node.op == '*':
return leftval * rightval
elif node.op == '/':
return leftval / rightval
def evaluate(exp):
toks = tokenize(exp)
tree = parse(toks)
return Evaluator().visit(tree)
exp = '2 * 3 + 5 / 2'
print(evaluate(exp))
exp = '+'.join([str(x) for x in range(10000)])
print(evaluate(exp))
output:
python3 compiler.py
8.5
49995000
2.11.14 Context manager and generator
>>> import contextlib
>>> @contextlib.contextmanager
... def mylist():
... try:
... l = [1, 2, 3, 4, 5]
... yield l
... finally:
... print("exit scope")
...
>>> with mylist() as l:
... print(l)
...
[1, 2, 3, 4, 5]
exit scope
2.11. Generator 91
python-cheatsheet Documentation, Release 0.1.0
2.11.15 What @contextmanager actually doing?
# ref: PyCon 2014 - David Beazley
# define a context manager class
class GeneratorCM(object):
def __init__(self, gen):
self._gen = gen
def __enter__(self):
return next(self._gen)
def __exit__(self, *exc_info):
try:
if exc_info[0] is None:
next(self._gen)
else:
self._gen.throw(*exc_info)
raise RuntimeError
except StopIteration:
return True
except:
raise
# define a decorator
def contextmanager(func):
def run(*a, **k):
return GeneratorCM(func(*a, **k))
return run
# example of context manager
@contextmanager
def mylist():
try:
l = [1, 2, 3, 4, 5]
yield l
finally:
print("exit scope")
with mylist() as l:
print(l)
output:
$ python ctx.py
[1, 2, 3, 4, 5]
exit scope
92 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.11.16 profile code block
>>> import time
>>> @contextmanager
... def profile(msg):
... try:
... s = time.time()
... yield
... finally:
... e = time.time()
... print('{} cost time: {}'.format(msg, e - s))
...
>>> with profile('block1'):
... time.sleep(1)
...
block1 cost time: 1.00105595589
>>> with profile('block2'):
... time.sleep(3)
...
block2 cost time: 3.00104284286
2.11.17 yield from and __iter__
>>> class FakeGen:
... def __iter__(self):
... n = 0
... while True:
... yield n
... n += 1
... def __reversed__(self):
... n = 9527
... while True:
... yield n
... n -= 1
...
>>> def spam():
... yield from FakeGen()
...
>>> s = spam()
>>> next(s)
0
>>> next(s)
1
>>> next(s)
2
>>> next(s)
3
>>> def reversed_spam():
... yield from reversed(FakeGen())
...
>>> g = reversed_spam()
(continues on next page)
2.11. Generator 93
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
>>> next(g)
9527
>>> next(g)
9526
>>> next(g)
9525
2.11.18 yield from == await expression
# "await" include in pyhton3.5
import asyncio
import socket
# set socket and event loop
loop = asyncio.get_event_loop()
host = 'localhost'
port = 5566
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM,0)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
sock.setblocking(False)
sock.bind((host, port))
sock.listen(10)
@asyncio.coroutine
def echo_server():
while True:
conn, addr = yield from loop.sock_accept(sock)
loop.create_task(handler(conn))
@asyncio.coroutine
def handler(conn):
while True:
msg = yield from loop.sock_recv(conn, 1024)
if not msg:
break
yield from loop.sock_sendall(conn, msg)
conn.close()
# equal to
async def echo_server():
while True:
conn, addr = await loop.sock_accept(sock)
loop.create_task(handler(conn))
async def handler(conn):
while True:
msg = await loop.sock_recv(conn, 1024)
if not msg:
break
await loop.sock_sendall(conn, msg)
(continues on next page)
94 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
conn.close()
loop.create_task(echo_server())
loop.run_forever()
output: (bash 1)
$ nc localhost 5566
Hello
Hello
output: (bash 2)
$ nc localhost 5566
World
World
2.11.19 Closure in Python - using generator
# nonlocal version
>>> def closure():
... x = 5566
... def inner_func():
... nonlocal x
... x += 1
... return x
... return inner_func
...
>>> c = closure()
>>> c()
5567
>>> c()
5568
>>> c()
5569
# class version
>>> class Closure:
... def __init__(self):
... self._x = 5566
... def __call__(self):
... self._x += 1
... return self._x
...
>>> c = Closure()
>>> c()
5567
>>> c()
5568
>>> c()
5569
(continues on next page)
2.11. Generator 95
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
# generator version (best)
>>> def closure_gen():
... x = 5566
... while True:
... x += 1
... yield x
...
>>> g = closure_gen()
>>> next(g)
5567
>>> next(g)
5568
>>> next(g)
5569
2.11.20 Implement a simple scheduler
# idea: write an event loop(scheduler)
>>> def fib(n):
... if n <= 2:
... return 1
... return fib(n-1) + fib(n-2)
...
>>> def g_fib(n):
... for x in range(1, n + 1):
... yield fib(x)
...
>>> from collections import deque
>>> t = [g_fib(3), g_fib(5)]
>>> q = deque()
>>> q.extend(t)
>>> def run():
... while q:
... try:
... t = q.popleft()
... print(next(t))
... q.append(t)
... except StopIteration:
... print("Task done")
...
>>> run()
1
1
1
1
2
2
Task done
3
(continues on next page)
96 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
5
Task done
2.11.21 Simple round-robin with blocking
# ref: PyCon 2015 - David Beazley
# skill: using task and wait queue
from collections import deque
from select import select
import socket
tasks = deque()
w_read = {}
w_send = {}
def run():
while any([tasks, w_read, w_send]):
while not tasks:
# polling tasks
can_r, can_s,_ = select(w_read, w_send, [])
for _r in can_r:
tasks.append(w_read.pop(_r))
for _w in can_s:
tasks.append(w_send.pop(_w))
try:
task = tasks.popleft()
why,what = next(task)
if why == 'recv':
w_read[what] = task
elif why == 'send':
w_send[what] = task
else:
raise RuntimeError
except StopIteration:
pass
def server():
host = ('localhost', 5566)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(host)
sock.listen(5)
while True:
# tell scheduler want block
yield 'recv', sock
conn,addr = sock.accept()
tasks.append(client_handler(conn))
def client_handler(conn):
(continues on next page)
2.11. Generator 97
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
while True:
# tell scheduler want block
yield 'recv', conn
msg = conn.recv(1024)
if not msg:
break
# tell scheduler want block
yield 'send', conn
conn.send(msg)
conn.close()
tasks.append(server())
run()
2.11.22 simple round-robin with blocking and non-blocking
# this method will cause blocking hunger
from collections import deque
from select import select
import socket
tasks = deque()
w_read = {}
w_send = {}
def run():
while any([tasks, w_read, w_send]):
while not tasks:
# polling tasks
can_r,can_s,_ = select(w_read, w_send, [])
for _r in can_r:
tasks.append(w_read.pop(_r))
for _w in can_s:
tasks.append(w_send.pop(_w))
try:
task = tasks.popleft()
why,what = next(task)
if why == 'recv':
w_read[what] = task
elif why == 'send':
w_send[what] = task
elif why == 'continue':
print(what)
tasks.append(task)
else:
raise RuntimeError
except StopIteration:
pass
def fib(n):
(continues on next page)
98 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
if n <= 2:
return 1
return fib(n-1) + fib(n-2)
def g_fib(n):
for x in range(1, n + 1):
yield 'continue', fib(x)
tasks.append(g_fib(15))
def server():
host = ('localhost', 5566)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(host)
sock.listen(5)
while True:
yield 'recv', sock
conn,addr = sock.accept()
tasks.append(client_handler(conn))
def client_handler(conn):
while True:
yield 'recv', conn
msg = conn.recv(1024)
if not msg:
break
yield 'send', conn
conn.send(msg)
conn.close()
tasks.append(server())
run()
2.11.23 Asynchronous Generators
# PEP 525
#
# Need python-3.6 or above
>>> import asyncio
>>> async def slow_gen(n, t):
... for x in range(n):
... await asyncio.sleep(t)
... yield x
...
>>> async def task(n):
... async for x in slow_gen(n, 0.1):
... print(x)
...
(continues on next page)
2.11. Generator 99
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(task(3))
0
1
2
2.11.24 Asynchronous generators can have try..finally blocks
# Need python-3.6 or above
>>> import asyncio
>>> async def agen(t):
... try:
... await asyncio.sleep(t)
... yield 1 / 0
... finally:
... print("finally part")
...
>>> async def main(t=1):
... try:
... g = agen(t)
... await g.__anext__()
... except Exception as e:
... print(repr(e))
...
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(main(1))
finally part
ZeroDivisionError('division by zero',)
2.11.25 send value and throw exception into async generator
# Need python-3.6 or above
>>> import asyncio
>>> async def agen(n, t=0.1):
... try:
... for x in range(n):
... await asyncio.sleep(t)
... val = yield x
... print(f'get val: {val}')
... except RuntimeError as e:
... await asyncio.sleep(t)
... yield repr(e)
...
>>> async def main(n):
... g = agen(n)
... ret = await g.asend(None) + await g.asend('foo')
... print(ret)
(continues on next page)
100 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
... ret = await g.athrow(RuntimeError('Get RuntimeError'))
... print(ret)
...
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(main(5))
get val: foo
1
RuntimeError('Get RuntimeError',)
2.11.26 Simple async round-robin
# Need python-3.6 or above
>>> import asyncio
>>> from collections import deque
>>> async def agen(n, t=0.1):
... for x in range(n):
... await asyncio.sleep(t)
... yield x
...
>>> async def main():
... q = deque([agen(3), agen(5)])
... while q:
... try:
... g = q.popleft()
... ret = await g.__anext__()
... print(ret)
... q.append(g)
... except StopAsyncIteration:
... pass
...
>>> loop.run_until_complete(main())
0
0
1
1
2
2
3
4
2.11. Generator 101
python-cheatsheet Documentation, Release 0.1.0
2.11.27 Async generator get better performance than async iterator
# Need python-3.6 or above
>>> import time
>>> import asyncio
>>> class AsyncIter:
... def __init__(self, n):
... self._n = n
... def __aiter__(self):
... return self
... async def __anext__(self):
... ret = self._n
... if self._n == 0:
... raise StopAsyncIteration
... self._n -= 1
... return ret
...
>>> async def agen(n):
... for i in range(n):
... yield i
...
>>> async def task_agen(n):
... s = time.time()
... async for _ in agen(n): pass
... cost = time.time() - s
... print(f"agen cost time: {cost}")
...
>>> async def task_aiter(n):
... s = time.time()
... async for _ in AsyncIter(n): pass
... cost = time.time() - s
... print(f"aiter cost time: {cost}")
...
>>> n = 10 ** 7
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(task_agen(n))
agen cost time: 1.2698817253112793
>>> loop.run_until_complete(task_aiter(n))
aiter cost time: 4.168368101119995
2.11.28 Asynchronous Comprehensions
# PEP 530
#
# Need python-3.6 or above
>>> import asyncio
>>> async def agen(n, t):
... for x in range(n):
... await asyncio.sleep(t)
(continues on next page)
102 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
... yield x
>>> async def main():
... ret = [x async for x in agen(5, 0.1)]
... print(*ret)
... ret = [x async for x in agen(5, 0.1) if x < 3]
... print(*ret)
... ret = [x if x < 3 else -1 async for x in agen(5, 0.1)]
... print(*ret)
... ret = {f'{x}': x async for x in agen(5, 0.1)}
... print(ret)
>>> loop.run_until_complete(main())
0 1 2 3 4
0 1 2
0 1 2 -1 -1
{'0': 0, '1': 1, '2': 2, '3': 3, '4': 4}
# await in Comprehensions
>>> async def foo(t):
... await asyncio.sleep(t)
... return "foo"
...
>>> async def bar(t):
... await asyncio.sleep(t)
... return "bar"
...
>>> async def baz(t):
... await asyncio.sleep(t)
... return "baz"
...
>>> async def gen(*f, t=0.1):
... for x in f:
... await asyncio.sleep(t)
... yield x
...
>>> async def await_simple_task():
... ret = [await f(0.1) for f in [foo, bar]]
... print(ret)
... ret = {await f(0.1) for f in [foo, bar]}
... print(ret)
... ret = {f.__name__: await f(0.1) for f in [foo, bar]}
... print(ret)
...
>>> async def await_other_task():
... ret = [await f(0.1) for f in [foo, bar] if await baz(1)]
... print(ret)
... ret = {await f(0.1) for f in [foo, bar] if await baz(1)}
... print(ret)
... ret = {f.__name__: await f(0.1) for f in [foo, bar] if await baz(1)}
... print(ret)
...
(continues on next page)
2.11. Generator 103
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
>>> async def await_aiter_task():
... ret = [await f(0.1) async for f in gen(foo, bar)]
... print(ret)
... ret = {await f(0.1) async for f in gen(foo, bar)}
... print(ret)
... ret = {f.__name__: await f(0.1) async for f in gen(foo, bar)}
... print(ret)
... ret = [await f(0.1) async for f in gen(foo, bar) if await baz(1)]
... print(ret)
... ret = {await f(0.1) async for f in gen(foo, bar) if await baz(1)}
... print(ret)
... ret = {f.__name__: await f(0.1) async for f in gen(foo, bar) if await baz(1)}
...
>>> import asyncio
>>> asyncio.get_event_loop()
>>> loop.run_until_complete(await_simple_task())
['foo', 'bar']
{'bar', 'foo'}
{'foo': 'foo', 'bar': 'bar'}
>>> loop.run_until_complete(await_other_task())
['foo', 'bar']
{'bar', 'foo'}
{'foo': 'foo', 'bar': 'bar'}
>>> loop.run_until_complete(await_gen_task())
['foo', 'bar']
{'bar', 'foo'}
{'foo': 'foo', 'bar': 'bar'}
['foo', 'bar']
{'bar', 'foo'}
{'foo': 'foo', 'bar': 'bar'}
2.12 Typing
PEP 484, which provides a specification about what a type system should look like in Python3, introduced the concept
of type hints. Moreover, to better understand the type hints design philosophy, it is crucial to read PEP 483 that would
be helpful to aid a pythoneer to understand reasons why Python introduce a type system. The main goal of this cheat
sheet is to show some common usage about type hints in Python3.
Table of Contents
• Typing
– Without type check
– With type check
– Basic types
– Functions
– Classes
104 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
– Generator
– Asynchronous Generator
– Context Manager
– Asynchronous Context Manager
– Avoid None access
– Positional-only arguments
– Multiple return values
– Union[Any, None] == Optional[Any]
– Be careful of Optional
– Be careful of casting
– Forward references
– Postponed Evaluation of Annotations
– Type alias
– Define a NewType
– Using TypeVar as template
– Using TypeVar and Generic as class template
– Scoping rules for TypeVar
– Restricting to a fixed set of possible types
– TypeVar with an upper bound
– @overload
– Stub Files
2.12.1 Without type check
def fib(n):
a, b = 0, 1
for _ in range(n):
yield a
b, a = a + b, b
print([n for n in fib(3.6)])
output:
# errors will not be detected until runtime
$ python fib.py
Traceback (most recent call last):
File "fib.py", line 8, in <module>
print([n for n in fib(3.5)])
File "fib.py", line 8, in <listcomp>
(continues on next page)
2.12. Typing 105
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
print([n for n in fib(3.5)])
File "fib.py", line 3, in fib
for _ in range(n):
TypeError: 'float' object cannot be interpreted as an integer
2.12.2 With type check
# give a type hint
from typing import Generator
def fib(n: int) -> Generator:
a: int = 0
b: int = 1
for _ in range(n):
yield a
b, a = a + b, b
print([n for n in fib(3.6)])
output:
# errors will be detected before running
$ mypy --strict fib.py
fib.py:12: error: Argument 1 to "fib" has incompatible type "float"; expected "int"
2.12.3 Basic types
import io
import re
from collections import deque, namedtuple
from typing import (
Dict,
List,
Tuple,
Set,
Deque,
NamedTuple,
IO,
Pattern,
Match,
Text,
Optional,
Sequence,
Iterable,
Mapping,
MutableMapping,
Any,
(continues on next page)
106 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
)
# without initializing
x: int
# any type
y: Any
y = 1
y = "1"
# built-in
var_int: int = 1
var_str: str = "Hello Typing"
var_byte: bytes = b"Hello Typing"
var_bool: bool = True
var_float: float = 1.
var_unicode: Text = u'\u2713'
# could be none
var_could_be_none: Optional[int] = None
var_could_be_none = 1
# collections
var_set: Set[int] = {i for i in range(3)}
var_dict: Dict[str, str] = {"foo": "Foo"}
var_list: List[int] = [i for i in range(3)]
var_static_length_Tuple: Tuple[int, int, int] = (1, 2, 3)
var_dynamic_length_Tuple: Tuple[int, ...] = (i for i in range(10, 3))
var_deque: Deque = deque([1, 2, 3])
var_nametuple: NamedTuple = namedtuple('P', ['x', 'y'])
# io
var_io_str: IO[str] = io.StringIO("Hello String")
var_io_byte: IO[bytes] = io.BytesIO(b"Hello Bytes")
var_io_file_str: IO[str] = open(__file__)
var_io_file_byte: IO[bytes] = open(__file__, 'rb')
# re
p: Pattern = re.compile("(https?)://([^/\r\n]+)(/[^\r\n]*)?")
m: Optional[Match] = p.match("https://www.python.org/")
# duck types: list-like
var_seq_list: Sequence[int] = [1, 2, 3]
var_seq_tuple: Sequence[int] = (1, 2, 3)
var_iter_list: Iterable[int] = [1, 2, 3]
var_iter_tuple: Iterable[int] = (1, 2, 3)
# duck types: dict-like
var_map_dict: Mapping[str, str] = {"foo": "Foo"}
var_mutable_dict: MutableMapping[str, str] = {"bar": "Bar"}
2.12. Typing 107
python-cheatsheet Documentation, Release 0.1.0
2.12.4 Functions
from typing import Generator, Callable
# function
def gcd(a: int, b: int) -> int:
while b:
a, b = b, a % b
return a
# callback
def fun(cb: Callable[[int, int], int]) -> int:
return cb(55, 66)
# lambda
f: Callable[[int], int] = lambda x: x * 2
2.12.5 Classes
from typing import ClassVar, Dict, List
class Foo:
x: int = 1 # instance variable. default = 1
y: ClassVar[str] = "class var" # class variable
def __init__(self) -> None:
self.i: List[int] = [0]
def foo(self, a: int, b: str) -> Dict[int, str]:
return {a: b}
foo = Foo()
foo.x = 123
print(foo.x)
print(foo.i)
print(Foo.y)
print(foo.foo(1, "abc"))
2.12.6 Generator
from typing import Generator
# Generator[YieldType, SendType, ReturnType]
def fib(n: int) -> Generator[int, None, None]:
a: int = 0
b: int = 1
while n > 0:
yield a
(continues on next page)
108 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
b, a = a + b, b
n -= 1
g: Generator = fib(10)
i: Iterator[int] = (x for x in range(3))
2.12.7 Asynchronous Generator
import asyncio
from typing import AsyncGenerator, AsyncIterator
async def fib(n: int) -> AsyncGenerator:
a: int = 0
b: int = 1
while n > 0:
await asyncio.sleep(0.1)
yield a
b, a = a + b, b
n -= 1
async def main() -> None:
async for f in fib(10):
print(f)
ag: AsyncIterator = (f async for f in fib(10))
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
2.12.8 Context Manager
from typing import ContextManager, Generator, IO
from contextlib import contextmanager
@contextmanager
def open_file(name: str) -> Generator:
f = open(name)
yield f
f.close()
cm: ContextManager[IO] = open_file(__file__)
with cm as f:
print(f.read())
2.12. Typing 109
python-cheatsheet Documentation, Release 0.1.0
2.12.9 Asynchronous Context Manager
import asyncio
from typing import AsyncContextManager, AsyncGenerator, IO
from contextlib import asynccontextmanager
# need python 3.7 or above
@asynccontextmanager
async def open_file(name: str) -> AsyncGenerator:
await asyncio.sleep(0.1)
f = open(name)
yield f
await asyncio.sleep(0.1)
f.close()
async def main() -> None:
acm: AsyncContextManager[IO] = open_file(__file__)
async with acm as f:
print(f.read())
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
2.12.10 Avoid None access
import re
from typing import Pattern, Dict, Optional
# like c++
# std::regex url("(https?)://([^/\r\n]+)(/[^\r\n]*)?");
# std::regex color("^#?([a-f0-9]{6}|[a-f0-9]{3})$");
url: Pattern = re.compile("(https?)://([^/\r\n]+)(/[^\r\n]*)?")
color: Pattern = re.compile("^#?([a-f0-9]{6}|[a-f0-9]{3})$")
x: Dict[str, Pattern] = {"url": url, "color": color}
y: Optional[Pattern] = x.get("baz", None)
print(y.match("https://www.python.org/"))
output:
$ mypy --strict foo.py
foo.py:15: error: Item "None" of "Optional[Pattern[Any]]" has no attribute "match"
110 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.12.11 Positional-only arguments
# define arguments with names beginning with __
def fib(__n: int) -> int: # positional only arg
a, b = 0, 1
for _ in range(__n):
b, a = a + b, b
return a
def gcd(*, a: int, b: int) -> int: # keyword only arg
while b:
a, b = b, a % b
return a
print(fib(__n=10)) # error
print(gcd(10, 5)) # error
output:
mypy --strict foo.py
foo.py:1: note: "fib" defined here
foo.py:14: error: Unexpected keyword argument "__n" for "fib"
foo.py:15: error: Too many positional arguments for "gcd"
2.12.12 Multiple return values
from typing import Tuple, Iterable, Union
def foo(x: int, y: int) -> Tuple[int, int]:
return x, y
# or
def bar(x: int, y: str) -> Iterable[Union[int, str]]:
# XXX: not recommend declaring in this way
return x, y
a: int
b: int
a, b = foo(1, 2) # ok
c, d = bar(3, "bar") # ok
2.12. Typing 111
python-cheatsheet Documentation, Release 0.1.0
2.12.13 Union[Any, None] == Optional[Any]
from typing import List, Union
def first(l: List[Union[int, None]]) -> Union[int, None]:
return None if len(l) == 0 else l[0]
first([None])
# equal to
from typing import List, Optional
def first(l: List[Optional[int]]) -> Optional[int]:
return None if len(l) == 0 else l[0]
first([None])
2.12.14 Be careful of Optional
from typing import cast, Optional
def fib(n):
a, b = 0, 1
for _ in range(n):
b, a = a + b, b
return a
def cal(n: Optional[int]) -> None:
print(fib(n))
cal(None)
output:
# mypy will not detect errors
$ mypy foo.py
Explicitly declare
from typing import Optional
def fib(n: int) -> int: # declare n to be int
a, b = 0, 1
for _ in range(n):
b, a = a + b, b
return a
def cal(n: Optional[int]) -> None:
print(fib(n))
output:
112 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
# mypy can detect errors even we do not check None
$ mypy --strict foo.py
foo.py:11: error: Argument 1 to "fib" has incompatible type "Optional[int]"; expected
˓→"int"
2.12.15 Be careful of casting
from typing import cast, Optional
def gcd(a: int, b: int) -> int:
while b:
a, b = b, a % b
return a
def cal(a: Optional[int], b: Optional[int]) -> None:
# XXX: Avoid casting
ca, cb = cast(int, a), cast(int, b)
print(gcd(ca, cb))
cal(None, None)
output:
# mypy will not detect type errors
$ mypy --strict foo.py
2.12.16 Forward references
Based on PEP 484, if we want to reference a type before it has been declared, we have to use string literal to imply
that there is a type of that name later on in the file.
from typing import Optional
class Tree:
def __init__(
self, data: int,
left: Optional["Tree"], # Forward references.
right: Optional["Tree"]
) -> None:
self.data = data
self.left = left
self.right = right
Note: There are some issues that mypy does not complain about Forward References. Get further information from
Issue#948.
2.12. Typing 113
python-cheatsheet Documentation, Release 0.1.0
class A:
def __init__(self, a: A) -> None: # should fail
self.a = a
output:
$ mypy --strict type.py
$ echo $?
0
$ python type.py # get runtime fail
Traceback (most recent call last):
File "type.py", line 1, in <module>
class A:
File "type.py", line 2, in A
def __init__(self, a: A) -> None: # should fail
NameError: name 'A' is not defined
2.12.17 Postponed Evaluation of Annotations
New in Python 3.7
• PEP 563 - Postponed Evaluation of Annotations
Before Python 3.7
>>> class A:
... def __init__(self, a: A) -> None:
... self._a = a
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in A
NameError: name 'A' is not defined
After Python 3.7 (include 3.7)
>>> from __future__ import annotations
>>> class A:
... def __init__(self, a: A) -> None:
... self._a = a
...
Note: Annotation can only be used within the scope which names have already existed. Therefore, forward reference
does not support the case which names are not available in the current scope. Postponed evaluation of annotations
will become the default behavior in Python 4.0.
114 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.12.18 Type alias
Like typedef or using in c/c++
#include <iostream>
#include <string>
#include <regex>
#include <vector>
typedef std::string Url;
template<typename T> using Vector = std::vector<T>;
int main(int argc, char *argv[])
{
Url url = "https://python.org";
std::regex p("(https?)://([^/\r\n]+)(/[^\r\n]*)?");
bool m = std::regex_match(url, p);
Vector<int> v = {1, 2};
std::cout << m << std::endl;
for (auto it : v) std::cout << it << std::endl;
return 0;
}
Type aliases are defined by simple variable assignments
import re
from typing import Pattern, List
# Like typedef, using in c/c++
# PEP 484 recommend capitalizing alias names
Url = str
url: Url = "https://www.python.org/"
p: Pattern = re.compile("(https?)://([^/\r\n]+)(/[^\r\n]*)?")
m = p.match(url)
Vector = List[int]
v: Vector = [1., 2.]
2.12.19 Define a NewType
Unlike alias, NewType returns a separate type but is identical to the original type at runtime.
from sqlalchemy import Column, String, Integer
from sqlalchemy.ext.declarative import declarative_base
from typing import NewType, Any
# check mypy #2477
(continues on next page)
2.12. Typing 115
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
Base: Any = declarative_base()
# create a new type
Id = NewType('Id', int) # not equal alias, it's a 'new type'
class User(Base):
__tablename__ = 'User'
id = Column(Integer, primary_key=True)
age = Column(Integer, nullable=False)
name = Column(String, nullable=False)
def __init__(self, id: Id, age: int, name: str) -> None:
self.id = id
self.age = age
self.name = name
# create users
user1 = User(Id(1), 62, "Guido van Rossum") # ok
user2 = User(2, 48, "David M. Beazley") # error
output:
$ python foo.py
$ mypy --ignore-missing-imports foo.py
foo.py:24: error: Argument 1 to "User" has incompatible type "int"; expected "Id"
Further reading:
• Issue#1284
2.12.20 Using TypeVar as template
Like c++ template <typename T>
#include <iostream>
template <typename T>
T add(T x, T y) {
return x + y;
}
int main(int argc, char *argv[])
{
std::cout << add(1, 2) << std::endl;
std::cout << add(1., 2.) << std::endl;
return 0;
}
Python using TypeVar
from typing import TypeVar
(continues on next page)
116 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
T = TypeVar("T")
def add(x: T, y: T) -> T:
return x + y
add(1, 2)
add(1., 2.)
2.12.21 Using TypeVar and Generic as class template
Like c++ template <typename T> class
#include <iostream>
template<typename T>
class Foo {
public:
Foo(T foo) {
foo_ = foo;
}
T Get() {
return foo_;
}
private:
T foo_;
};
int main(int argc, char *argv[])
{
Foo<int> f(123);
std::cout << f.Get() << std::endl;
return 0;
}
Define a generic class in Python
from typing import Generic, TypeVar
T = TypeVar("T")
class Foo(Generic[T]):
def __init__(self, foo: T) -> None:
self.foo = foo
def get(self) -> T:
return self.foo
f: Foo[str] = Foo("Foo")
v: int = f.get()
output:
2.12. Typing 117
python-cheatsheet Documentation, Release 0.1.0
$ mypy --strict foo.py
foo.py:13: error: Incompatible types in assignment (expression has type "str", variable␣
˓→has type "int")
2.12.22 Scoping rules for TypeVar
• TypeVar used in different generic function will be inferred to be different types.
from typing import TypeVar
T = TypeVar("T")
def foo(x: T) -> T:
return x
def bar(y: T) -> T:
return y
a: int = foo(1) # ok: T is inferred to be int
b: int = bar("2") # error: T is inferred to be str
output:
$ mypy --strict foo.py
foo.py:12: error: Incompatible types in assignment (expression has type "str", variable␣
˓→has type "int")
• TypeVar used in a generic class will be inferred to be same types.
from typing import TypeVar, Generic
T = TypeVar("T")
class Foo(Generic[T]):
def foo(self, x: T) -> T:
return x
def bar(self, y: T) -> T:
return y
f: Foo[int] = Foo()
a: int = f.foo(1) # ok: T is inferred to be int
b: str = f.bar("2") # error: T is expected to be int
output:
$ mypy --strict foo.py
foo.py:15: error: Incompatible types in assignment (expression has type "int", variable␣
˓→has type "str")
foo.py:15: error: Argument 1 to "bar" of "Foo" has incompatible type "str"; expected "int
˓→"
118 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
• TypeVar used in a method but did not match any parameters which declare in Generic can be inferred to be
different types.
from typing import TypeVar, Generic
T = TypeVar("T")
S = TypeVar("S")
class Foo(Generic[T]): # S does not match params
def foo(self, x: T, y: S) -> S:
return y
def bar(self, z: S) -> S:
return z
f: Foo[int] = Foo()
a: str = f.foo(1, "foo") # S is inferred to be str
b: int = f.bar(12345678) # S is inferred to be int
output:
$ mypy --strict foo.py
• TypeVar should not appear in body of method/function if it is unbound type.
from typing import TypeVar, Generic
T = TypeVar("T")
S = TypeVar("S")
def foo(x: T) -> None:
a: T = x # ok
b: S = 123 # error: invalid type
output:
$ mypy --strict foo.py
foo.py:8: error: Invalid type "foo.S"
2.12.23 Restricting to a fixed set of possible types
T = TypeVar('T', ClassA, ...) means we create a type variable with a value restriction.
from typing import TypeVar
# restrict T = int or T = float
T = TypeVar("T", int, float)
def add(x: T, y: T) -> T:
return x + y
add(1, 2)
(continues on next page)
2.12. Typing 119
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
add(1., 2.)
add("1", 2)
add("hello", "world")
output:
# mypy can detect wrong type
$ mypy --strict foo.py
foo.py:10: error: Value of type variable "T" of "add" cannot be "object"
foo.py:11: error: Value of type variable "T" of "add" cannot be "str"
2.12.24 TypeVar with an upper bound
T = TypeVar('T', bound=BaseClass) means we create a type variable with an upper bound. The concept is
similar to polymorphism in c++.
#include <iostream>
class Shape {
public:
Shape(double width, double height) {
width_ = width;
height_ = height;
};
virtual double Area() = 0;
protected:
double width_;
double height_;
};
class Rectangle: public Shape {
public:
Rectangle(double width, double height)
:Shape(width, height)
{};
double Area() {
return width_ * height_;
};
};
class Triangle: public Shape {
public:
Triangle(double width, double height)
:Shape(width, height)
{};
double Area() {
return width_ * height_ / 2;
};
};
(continues on next page)
120 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
double Area(Shape &s) {
return s.Area();
}
int main(int argc, char *argv[])
{
Rectangle r(1., 2.);
Triangle t(3., 4.);
std::cout << Area(r) << std::endl;
std::cout << Area(t) << std::endl;
return 0;
}
Like c++, create a base class and TypeVar which bounds to the base class. Then, static type checker will take every
subclass as type of base class.
from typing import TypeVar
class Shape:
def __init__(self, width: float, height: float) -> None:
self.width = width
self.height = height
def area(self) -> float:
return 0
class Rectangle(Shape):
def area(self) -> float:
width: float = self.width
height: float = self.height
return width * height
class Triangle(Shape):
def area(self) -> float:
width: float = self.width
height: float = self.height
return width * height / 2
S = TypeVar("S", bound=Shape)
def area(s: S) -> float:
return s.area()
r: Rectangle = Rectangle(1, 2)
(continues on next page)
2.12. Typing 121
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
t: Triangle = Triangle(3, 4)
i: int = 5566
print(area(r))
print(area(t))
print(area(i))
output:
$ mypy --strict foo.py
foo.py:40: error: Value of type variable "S" of "area" cannot be "int"
2.12.25 @overload
Sometimes, we use Union to infer that the return of a function has multiple different types. However, type checker
cannot distinguish which type do we want. Therefore, following snippet shows that type checker cannot determine
which type is correct.
from typing import List, Union
class Array(object):
def __init__(self, arr: List[int]) -> None:
self.arr = arr
def __getitem__(self, i: Union[int, str]) -> Union[int, str]:
if isinstance(i, int):
return self.arr[i]
if isinstance(i, str):
return str(self.arr[int(i)])
arr = Array([1, 2, 3, 4, 5])
x:int = arr[1]
y:str = arr["2"]
output:
$ mypy --strict foo.py
foo.py:16: error: Incompatible types in assignment (expression has type "Union[int, str]
˓→", variable has type "int")
foo.py:17: error: Incompatible types in assignment (expression has type "Union[int, str]
˓→", variable has type "str")
Although we can use cast to solve the problem, it cannot avoid typo and cast is not safe.
from typing import List, Union, cast
class Array(object):
def __init__(self, arr: List[int]) -> None:
(continues on next page)
122 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
(continued from previous page)
self.arr = arr
def __getitem__(self, i: Union[int, str]) -> Union[int, str]:
if isinstance(i, int):
return self.arr[i]
if isinstance(i, str):
return str(self.arr[int(i)])
arr = Array([1, 2, 3, 4, 5])
x: int = cast(int, arr[1])
y: str = cast(str, arr[2]) # typo. we want to assign arr["2"]
output:
$ mypy --strict foo.py
$ echo $?
0
Using @overload can solve the problem. We can declare the return type explicitly.
from typing import Generic, List, Union, overload
class Array(object):
def __init__(self, arr: List[int]) -> None:
self.arr = arr
@overload
def __getitem__(self, i: str) -> str:
...
@overload
def __getitem__(self, i: int) -> int:
...
def __getitem__(self, i: Union[int, str]) -> Union[int, str]:
if isinstance(i, int):
return self.arr[i]
if isinstance(i, str):
return str(self.arr[int(i)])
arr = Array([1, 2, 3, 4, 5])
x: int = arr[1]
y: str = arr["2"]
output:
$ mypy --strict foo.py
$ echo $?
0
2.12. Typing 123
python-cheatsheet Documentation, Release 0.1.0
Warning: Based on PEP 484, the @overload decorator just for type checker only, it does not implement the
real overloading like c++/java. Thus, we have to implement one exactly non-@overload function. At the runtime,
calling the @overload function will raise NotImplementedError.
from typing import List, Union, overload
class Array(object):
def __init__(self, arr: List[int]) -> None:
self.arr = arr
@overload
def __getitem__(self, i: Union[int, str]) -> Union[int, str]:
if isinstance(i, int):
return self.arr[i]
if isinstance(i, str):
return str(self.arr[int(i)])
arr = Array([1, 2, 3, 4, 5])
try:
x: int = arr[1]
except NotImplementedError as e:
print("NotImplementedError")
output:
$ python foo.py
NotImplementedError
2.12.26 Stub Files
Stub files just like header files which we usually use to define our interfaces in c/c++. In python, we can define our
interfaces in the same module directory or export MYPYPATH=${stubs}
First, we need to create a stub file (interface file) for module.
$ mkdir fib
$ touch fib/__init__.py fib/__init__.pyi
Then, define the interface of the function in __init__.pyi and implement the module.
# fib/__init__.pyi
def fib(n: int) -> int: ...
# fib/__init__.py
def fib(n):
a, b = 0, 1
for _ in range(n):
b, a = a + b, b
return a
124 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
Then, write a test.py for testing fib module.
# touch test.py
import sys
from pathlib import Path
p = Path(__file__).parent / "fib"
sys.path.append(str(p))
from fib import fib
print(fib(10.0))
output:
$ mypy --strict test.py
test.py:10: error: Argument 1 to "fib" has incompatible type "float"; expected "int"
2.13 Datetime
Table of Contents
• Datetime
– Timestamp
– Date
– Format
– Convert date to datetime
2.13.1 Timestamp
>>> import time
>>> time.time()
1613526236.395773
>>> datetime.utcnow()
datetime.datetime(2021, 2, 17, 1, 45, 19, 312513)
>>> t = time.time()
>>> datetime.fromtimestamp(t)
datetime.datetime(2021, 2, 17, 9, 45, 41, 95756)
>>> d = datetime.fromtimestamp(t)
>>> d.timestamp()
1613526341.095756
2.13. Datetime 125
python-cheatsheet Documentation, Release 0.1.0
2.13.2 Date
>>> from datetime import date
>>> date.today()
datetime.date(2021, 2, 17)
2.13.3 Format
>>> from datetime import datetime
>>> d = datetime.utcnow()
>>> d.isoformat()
'2021-02-17T02:26:59.584044'
2.13.4 Convert date to datetime
>>> from datetime import datetime, date
>>> today = date.today()
>>> d = datetime.combine(today, datetime.min.time())
>>> d
datetime.datetime(2021, 2, 17, 0, 0)
2.14 Files and I/O
Table of Contents
• Files and I/O
– Read a File
– Readline
– Reading File Chunks
– Write a File
– Create a Symbolic Link
– Copy a File
– Move a File
– List a Directory
– Create Directories
– Copy a Directory
– Remove a Directory
– Path Join
– Get Absolute Path
126 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
– Get Home Directory
– Get Current Directory
– Get Path Properties
– Read a gzip CSV
– Linux Inotify
2.14.1 Read a File
In Python 2, the content of the file which read from file system does not decode. That is, the content of the file is a byte
string, not a Unicode string.
>>> with open("/etc/passwd") as f:
... content = f.read()
>>> print(type(content))
<type 'str'>
>>> print(type(content.decode("utf-8")))
<type 'unicode'>
In Python 3, open provides encoding option. If files do not open in binary mode, the encoding will be determined by
locale.getpreferredencoding(False) or user’s input.
>>> with open("/etc/hosts", encoding="utf-8") as f:
... content = f.read()
...
>>> print(type(content))
<class 'str'>
Binary mode
>>> with open("/etc/hosts", "rb") as f:
... content = f.read()
...
>>> print(type(content))
<class 'bytes'>
2.14.2 Readline
>>> with open("/etc/hosts") as f:
... for line in f:
... print(line, end='')
...
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
2.14. Files and I/O 127
python-cheatsheet Documentation, Release 0.1.0
2.14.3 Reading File Chunks
>>> chunk_size = 16
>>> content = ''
>>> with open('/etc/hosts') as f:
... for c in iter(lambda: f.read(chunk_size), ''):
... content += c
...
>>> print(content)
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
2.14.4 Write a File
>>> content = "Awesome Python!"
>>> with open("foo.txt", "w") as f:
... f.write(content)
2.14.5 Create a Symbolic Link
>>> import os
>>> os.symlink("foo", "bar")
>>> os.readlink("bar")
'foo'
2.14.6 Copy a File
>>> from distutils.file_util import copy_file
>>> copy_file("foo", "bar")
('bar', 1)
2.14.7 Move a File
>>> from distutils.file_util import move_file
>>> move_file("./foo", "./bar")
'./bar'
128 Chapter 2. Cheat Sheet
python-cheatsheet Documentation, Release 0.1.0
2.14.8 List a Directory
>>> >>> import os
>>> dirs = os.listdir(".")
After Python 3.6, we can use os.scandir to list a directory. It is more convenient because os.scandir return
an iterator of os.DirEntry objects. In this case, we can get file information through access the attributes of os.
DirEntry. Further information can be found on the document.
>>> with os.scandir("foo") as it:
... for entry in it:
... st = entry.stat()
...
2.14.9 Create Directories
Similar to mkdir -p /path/to/dest
>>> from distutils.dir_util import mkpath
>>> mkpath("foo/bar/baz")
['foo', 'foo/bar', 'foo/bar/baz']
2.14.10 Copy a Directory
>>> from distutils.dir_util import copy_tree
>>> copy_tree("foo", "bar")
['bar/baz']
2.14.11 Remove a Directory
>>> from distutils.dir_util import remove_tree
>>> remove_tree("dir")
2.14.12 Path Join
>>> from pathlib import Path
>>> p = Path("/Users")
>>> p = p / "Guido" / "pysheeet"
>>> p
PosixPath('/Users/Guido/pysheeet')
2.14. Files and I/O 129
python-cheatsheet Documentation, Release 0.1.0
2.14.13 Get Absolute Path
>>> from pathlib import Path
>>> p = Path("README.rst")
PosixPath('/Users/Guido/pysheeet/README.rst')
2.14.14 Get Home Directory
>>> from pathlib import Path
>>> Path.home()
PosixPath('/Users/Guido')
2.14.15 Get Current Directory
>>> from pathlib import Path
>>> p = Path("README.rst")
>>> p.cwd()
PosixPath('/Users/Guido/pysheeet')
2.14.16 Get Path Properties
>>> from pathlib import Path
>>> p = Path("README.rst").absolute()
>>> p.root
'/'
>>> p.anchor
'/'
>>> p.parent
PosixPath('/Users/Guido/pysheeet')
>>> p.parent.parent
PosixPath('/Users/Guido')
>>> p.name
'README.rst'
>>> p.suffix
'.rst'
>>> p.stem
'README'
>>> p.as_uri()
'file:///Users/Guido/pysheeet/README.rst'
130 Chapter 2. Cheat Sheet