📜 ⬆️ ⬇️

Compilation @pythonetc, December 2018



This is the seventh collection of tips on 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 earlier you could use the contextlib.nested function:

 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 you to enter any number of contexts at any time and guarantees to 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 interpreter’s memory can be accessed using gc.get_objects() :

 In : class A: ...: def __init__(self, x): ...: self._x = x ...: ...: def __repr__(self): ...: class_name = type(self).__name__ ...: x = self._x ...: return f'{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 the numbers of several hundred characters. Full list here .

This has implications 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, datetime.time() objects were considered false if they represented midnight UTC. This can lead to non-obvious bugs. In the following example, if not may not be executed, not because create_time
is None , but because it is midnight.

 def create(created_time=None) -> None: if not created_time: created_time = datetime.now().time() 

You can work around this bug by explicitly checking for 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, use the loop.run_in_executor method.

For you, this can be done by a third-party aiofiles module, which provides a convenient and simple interface:

 async with aiofiles.open('filename', mode='r') as f: contents = await f.read() 

Source: https://habr.com/ru/post/436322/