company_banner

Подборка @pythonetc, декабрь 2018



    Это седьмая подборка советов про Python и программирование из моего авторского канала @pythonetc.

    Предыдущие подборки:


    Множественные контексты


    Иногда бывает нужно запустить какой-то блок кода в нескольких менеджерах контекста:

    with open('f') as f:
        with open('g') as g:
            with open('h') as h:
                pass

    Со времён Python 2.7 и 3.1 это можно сделать с помощью одного выражения:

    o = open
    with o('f') as f, o('g') as g, o('h') as h:
        pass

    А раньше можно было воспользоваться функцией contextlib.nested:

    with nested(o('f'), o('g'), o('h')) as (f, g, h):
        pass

    Если вы работаете с неопределённым количеством менеджеров контекста, то лучше выбрать более продвинутые инструменты. contextlib.ExitStack позволяет в любое время входить в любое количество контекстов и гарантирует выход из них по окончании исполнения:

    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
        ]
    

    Объекты в памяти интерпретатора


    Ко всем объектам, которые в данный момент находятся в памяти интерпретатора, можно получить доступ с помощью 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)]
    

    Символы-цифры


    In : int('୧৬༣')
    Out: 163

    0 1 2 3 4 5 6 7 8 9 — это не единственные символы, считающиеся цифрами. Python соблюдает правила Unicode и считает цифрами несколько сотен символов. Полный список здесь.

    Это имеет значение для функций вроде int, unicode.isdecimal и даже re.match:

    In : int('௯')
    Out: 9
    
    In : '٢'.isdecimal()
    Out: True
    
    In : bool(re.match('\d', '౫'))
    Out: True

    Полночь по UTC


    >>> bool(datetime(2018, 1, 1).time())
    False
    >>> bool(datetime(2018, 1, 1, 13, 12, 11).time())
    True

    До Pyhon 3.5 объекты datetime.time() считались ложными, если они представляли полночь по UTC. Это может приводить к неочевидным багам. В следующем примере if not может не выполниться не потому, что create_time
    является None, а потому что это полночь.

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

    Обойти этот баг можно с помощью явной проверки на None: if created_time is None.

    Асинхронная работа в ФС


    Python не поддерживает асинхронные операции с файлами. Чтобы сделать их неблокирующими, приходится использовать треды.

    Для асинхронного исполнения кода в потоке нужно использовать метод loop.run_in_executor.

    За вас это может сделать сторонний модуль aiofiles, предоставляющий удобный и простой интерфейс:

    async with aiofiles.open('filename', mode='r') as f:
        contents = await f.read()
    
    • +35
    • 5,1k
    • 4
    Mail.ru Group
    1816,00
    Строим Интернет
    Поделиться публикацией

    Похожие публикации

    Комментарии 4

      0
      > До Pyhon 3.5 объекты datetime.time() считались ложными

      да, неочевидная штука
        0
        return f'{class_name}({x!r})'


        а {x!r} это можно поподробней?

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое