Подборка @pythonetc, октябрь 2019

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

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

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


Если хотите итерировать сразу несколько итерируемых объектов, то можете использовать функцию zip (не имеет никакого отношения к файловому формату ZIP):

from datetime import timedelta

names = [
    'Eleven. Return and Revert',
    'Wilderness',
    'The Menagerie Inside',
    'Evaporate',
]

years = [
    2010,
    2013,
    2015,
    2018,
]

durations = [
    timedelta(minutes=57, seconds=38),
    timedelta(minutes=48, seconds=5),
    timedelta(minutes=46, seconds=34),
    timedelta(minutes=43, seconds=25),
]

print('Midas Fall LPs:')
for name, year, duration in zip(
    names, years, durations
):
    print(f'  * {name} ({year}) — {duration}')

Результат:

Midas Fall LPs:
  * Eleven. Return and Revert (2010) — 0:57:38
  * Wilderness (2013) — 0:48:05
  * The Menagerie Inside (2015) — 0:46:34
  * Evaporate (2018) — 0:43:25


Генератор можно остановить явным вызовом g.close(), но чаще всего сборщик мусора делает это за вас. После вызова close, в точке, где генерирующая функция была поставлена на паузу, инициируется GeneratorExit:

def gen():
    try:
        yield 1
        yield 2
    finally:
        print('END')


g = gen()
print(next(g))  # prints '1'
g.close()  # prints 'END'

Не забывайте о трёх аспектах. Во-первых, вы не можете продолжать генерировать значения при обработке GeneratorExit:

def gen():
    try:
        yield 1
    finally:
        yield 3


g = gen()
next(g)
g.close()  # RuntimeError

Во-вторых, если генератор ещё не запущен, то исключение не будет брошено, но генератор все равно перейдет в состояние «остановлен»:

def gen():
    try:
        yield 1
    finally:
        print('END')


g = gen()
g.close()  # nothing
print(list(g))  # prints '[]'

В-третьих, close ничего не делает, если генератор уже закончил работу:

def gen():
    try:
        yield 1
        yield 2
    finally:
        print('END')


g = gen()
print(list(g))
print('Closing now')
g.close()

# END
# [1, 2]
# Closing now


f-строки позволяют задавать ширину выводимого значения, а также другие форматирующие спецификаторы:

>>> x = 42
>>> f'{x:5}+{x:15f}'
'   42+      42.000000'

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

def print_table(matrix):
    cols_width = [
        max(len(str(row[col])) for row in matrix)
        for col in range(len(matrix[0]))
    ]

    for row in matrix:
        for i, cell in enumerate(row):
            print(
                f'{cell:{cols_width[i]}} ',
                end=''
            )
        print()

albums = [
    ['Eleven. Return and Revert', 2010],
    ['Wilderness', 2013],
    ['The Menagerie Inside', 2015],
    ['Evaporate', 2018],
]

print_table(albums)

Результат:

Eleven. Return and Revert 2010
Wilderness                2013
The Menagerie Inside      2015
Evaporate                 2018


Если ваш класс является производным от другого, то метакласс вашего класса тоже должен быть производным от метакласса того класса:

from collections import UserDict
from abc import ABCMeta

# ABCMeta is a metaclass of UserDict
class MyDictMeta(ABCMeta):
    def __new__(cls, name, bases, dct):
        return super().__new__(cls, name, bases, dct)

class MyDict(UserDict, metaclass=MyDictMeta):
    pass

Может быть целесообразно автоматически получать метакласс этого другого класса:

def create_my_dict_class(parents):
    class MyDictMeta(*[type(c) for c in parents]):
        def __new__(cls, name, bases, dct):
            return super().__new__(cls, name, bases, dct)

    class MyDict(*parents, metaclass=MyDictMeta):
        pass


MyDict = create_my_dict_class((UserDict,))


__init__ позволяет модифицировать объект сразу после его создания. Если хотите контролировать созданное, то используйте __new__:

from typing import Tuple, Dict
from cached_property import cached_property


class Numbers:
    _LOADED: Dict[Tuple[int, ...], 'Numbers'] = {}

    def __new__(cls, ints: Tuple[int, ...]):
        if ints not in cls._LOADED:
            obj = super().__new__(cls)
            cls._LOADED[ints] = obj

        return cls._LOADED[ints]

    def __init__(self, ints: Tuple[int, ...]):
        self._ints = ints

    @cached_property
    def biggest(self):
        print('calculating...')
        return max(self._ints)


print(Numbers((4, 3, 5)).biggest)
print(Numbers((4, 3, 5)).biggest)
print(Numbers((4, 3, 6)).biggest)
Источник: https://habr.com/ru/company/mailru/blog/475684/


Интересные статьи

Интересные статьи

Возможность интеграции с «1С» — это ключевое преимущество «1С-Битрикс» для всех, кто профессионально занимается продажами в интернете, особенно для масштабных интернет-магазинов.
Сегодня мы поделимся итогами четвертой по счету программы летнего обучения Summ3r 0f h4ck в нашей компании в отделе исследований.
С чего начинается конференция? Конечно, с бейджа! Это первое, что ты получаешь на входе, целый день (или несколько) вы с ним неразлучны, а потом он висит над твоим столом, напоминая окружающи...
Уже завтра начнётся седьмая по счёту конференция HolyJS. С каждым годом работа над её программой всё сложнее не только из-за стремительного развития и взросления JS-экосистемы, но и из-за рос...
Привет, Хабр! Две недели назад мы выпустили GoLand 2019.1 и спешим рассказать вам о новинках этого релиза.