Compilation @pythonetc, December 2018
![](https://habrastorage.org/webt/ym/yr/ke/ymyrkeb-wvhtziekuyiqlmijpak.png)
This is the seventh collection of tips about Python and programming from my author’s @pythonetc channel.
Previous selections:
Multiple contexts
Sometimes you need to run some block of code in several context managers:
with open('f') as f:
with open('g') as g:
with open('h') as h:
pass
Since the days of Python 2.7 and 3.1, this can be done with a single expression:
o = open
with o('f') as f, o('g') as g, o('h') as h:
pass
And before that you could use the function
contextlib.nested
:with nested(o('f'), o('g'), o('h')) as (f, g, h):
pass
If you are working with an unspecified number of context managers, it is better to choose more advanced tools.
contextlib.ExitStack
allows to enter any number of contexts at any time and guarantees exit from them at the end of execution:with ExitStack() as stack:
f = stack.enter_context(o('f'))
g = stack.enter_context(o('g'))
other = [
stack.enter_context(o(filename))
for filename in filenames
]
Objects in interpreter memory
All objects that are currently in the memory of the interpreter can be accessed using
gc.get_objects()
:In : classA:
...: def__init__(self, x):
...: self._x = x
...:
...: def__repr__(self):
...: class_name = type(self).__name__
...: x = self._x
...: returnf'{class_name}({x!r})'
...:
In : A(1)
Out: A(1)
In : A(2)
Out: A(2)
In : A(3)
Out: A(3)
In : [x for x in gc.get_objects() if isinstance(x, A)]
Out: [A(1), A(2), A(3)]
Character Numbers
In : int('୧৬༣')
Out: 163
0 1 2 3 4 5 6 7 8 9
- These are not the only characters that are considered numbers. Python follows the rules of Unicode and counts numbers as hundreds of characters. Full list here . It matters for functions like
int
, unicode.isdecimal
and even re.match
:In : int('௯')
Out: 9
In : '٢'.isdecimal()
Out: True
In : bool(re.match('\d', '౫'))
Out: True
Midnight UTC
>>> bool(datetime(2018, 1, 1).time())
False>>> bool(datetime(2018, 1, 1, 13, 12, 11).time())
True
Before Pyhon 3.5, objects
datetime.time()
were considered false if they represented midnight UTC. This can lead to unobvious bugs. In the following example, it if not
may not be executed, not because it create_time
is
None
, but because it is midnight.defcreate(created_time=None) -> None:ifnot created_time:
created_time = datetime.now().time()
Around this bug, you can use explicit checks on
None
: if created_time is None
.Asynchronous work in FS
Python does not support asynchronous file operations. To make them non-blocking, you have to use threads.
For asynchronous code execution in a stream, you need to use the method
loop.run_in_executor
. For you this can be done by a third-party module
aiofiles
that provides a convenient and simple interface:asyncwith aiofiles.open('filename', mode='r') as f:
contents = await f.read()