Несколько продвинутых приемов языка Python

Сделали для вас небольшую подборку приемов в Python, которые, надеемся, существенно облегчат вам работу. Советуем статью продвинутым пользователям.





Python полон удивительных функций и трюков, которые заставляют вас думать: «Ух ты! Python так крут!». Мы собрали несколько функций, которые нам особенно нравятся. Мы надеемся, что вы узнаете что-то, что заставит вас сказать: «Вот это да! Я этого не знал».
Исходный код на GitHub , если у вас есть идеи по его улучшению, добро пожаловать!

Генераторы в Python

Генератор представляет собой объект, который создает последовательность значений. Он может использоваться как итератор, а это означает, что вы можете применять его с оператором for или использовать функцию next для получения следующего значения. Однако перебирать значения вы можете только один раз.
Генератор может быть создан благодаря функции, ключевым словом которой служит yield (создает значение). Когда вызывается функция генератора, создается объект-генератор.

def fibonacci_generator():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

# Печатает все числа последовательности Фибоначчи, меньше 1000
for i in fibonacci_generator():
    if  i > 1000:
        break
    print(i)

 

Для простых случаев можно создать генератор, используя выражение-генератор. В отличие от списка, значения будут вычисляться «на лету», а не захламлять ими память для одноразового вычисления.


a = (x * x for x in range(100))

# a объект-генератор
print(type(a))

# Сумма всех числе
print(sum(a))

# В генераторе не осталось чисел
print(sum(a))

Модуль Collections

Collections представляет собой модуль в стандартной библиотеке, которая реализует контейнеры альтернативных типов данных.
Например, counter представляет собой совокупность элементов, которые хранятся в виде ключей словаря, а их счетчики в виде значений словаря:


from collections import Counter

a = Counter('blue')
b = Counter('yellow')

print(a)
print(b)
print((a + b).most_common(3))

Defaultdict подкласс dict, который позволяет использовать функцию factory, используемую для автоматического создания нового значения , в случае отсутствия ключа.


from collections import defaultdict

my_dict = defaultdict(lambda: 'Default Value')
my_dict['a'] = 42

print(my_dict['a'])
print(my_dict['b'])

Defaultdict может быть использован для создания древовидной структуры данных!


from collections import defaultdict
import json

def tree():
    """
    Factory that creates a defaultdict that also uses this factory
    """
    return defaultdict(tree)

root = tree()
root['Page']['Python']['defaultdict']['Title'] = 'Using defaultdict'
root['Page']['Python']['defaultdict']['Subtitle'] = 'Create a tree'
root['Page']['Java'] = None

print(json.dumps(root, indent=4))

Модуль Itertools

itertools представляет собой модуль в стандартной библиотеке , позволяющий создавать итераторы для эффективного зацикливания.
Например, permutations позволяет генерировать все возможные способы упорядочения набора вещей:


from itertools import permutations

for p in permutations([1,2,3]):
    print(p)	

Аналогичным образом , combinations создает все возможные способы выбора предметов из коллекции, так , что ( в отличии от permutations) порядок не имеет значения:


from itertools import combinations

for c in combinations([1, 2, 3, 4], 2):
    print(c)

itertools также содержит вспомогательные функции , такие как chain, которая принимает итерируемую и создает новый итератор , который возвращает элементы из данных поочередно, в виде одной последовательности:


from itertools import chain

for c in chain(range(3), range(12, 15)):
    print(c)

Упаковка / Распаковка в Python

* - оператор, известный как распаковочный или splat-оператор, позволяет делать очень удобные преобразования, переходя из списков или кортежей отдельной переменной или аргументов и наоборот.


a, *b, c = [2, 7, 5, 6, 3, 4, 1]
print(a)
print(b)
print(c)

Когда аргументы вашей функции уже в списке или в кортеже, вы можете распаковать их с помощью * args , если это список, или ** kwargs , если это dict.


def repeat(count, name):
    for i in range(count):
        print(name)

print("Call function repeat using a list of arguments:")
args = [4, "cats"]
repeat(*args)

print("Call function repeat using a dictionary of keyword arguments:")
args2 = {'count': 4, 'name': 'cats'}
repeat(**args2)

Возможна и обратная операция: вы можете определить функцию, которая будет упаковывать все аргументы в одном кортеже и все ключевые слова в один dict.


def f(*args, **kwargs):
    print("Arguments: ", args)
    print("Keyword arguments: ", kwargs)

f(3, 4, 9, foo=42, bar=7)

Декораторы в Python

decorator функция, которая принимает функцию в качестве параметра и возвращает функцию.
Например, в коде ниже, кэш-функция используется в качестве decorator, чтобы хранить числа Фибоначчи, которые уже были вычислены:

def cache(function):
    cached_values = {}  # Cодержит уже посчитанные числа
    def wrapping_function(*args):
        if args not in cached_values:
            # Вызывает функцию только если мы еще не сделали этого для этих параметров

            cached_values[args] = function(*args)
        return cached_values[args]
    return wrapping_function

@cache
def fibonacci(n):
    print('calling fibonacci(%d)' % n)
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print([fibonacci(n) for n in range(1, 9)])

 

Functools модуль обеспечивает нас несколькими decorator-ами, такими как lru_cache , которые могут делать то , что мы сделали только что: запоминание. Он сохраняет недавние вызовы, чтобы сэкономить время, когда функция вызывается с теми же аргументами:

from functools import lru_cache

@lru_cache(maxsize=None)
def fibonacci(n):
    print('calling fibonacci(%d)' % n)
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print([fibonacci(n) for n in range(1, 9)])

 

Менеджеры контекста

Менеджеры контекста в основном используются для правильного управления ресурсами. Наиболее часто они используются для открытия файла: open('workfile', 'r') as f:. Однако большинство разработчиков не знают, как все они работают на самом деле и как создать свой собственный.
На самом деле, менеджер контекста это просто класс , который реализует методы __enter__ и __exit__.


	from time import time


class Timer():
    def __init__(self, message):
        self.message = message

    def __enter__(self):
        self.start = time()
        return None  # Возвращает что угодно, чтобы использовать следующим образом:
        Timer("Message") as value:

    def __exit__(self, type, value, traceback):
        elapsed_time = (time() - self.start) * 1000
        print(self.message.format(elapsed_time))


with Timer("Elapsed time to compute some prime numbers: {}ms"):
    primes = []
    for x in range(2, 500):
        if not any(x % p == 0 for p in primes):
            primes.append(x)
    print("Primes: {}".format(primes))

В простых случаях можно использовать генератор функций с одним yield, используя декоратор @contextmanager .


from contextlib import contextmanager


@contextmanager
def colored_output(color):
    print("\033[%sm" % color, end="")
    yield
    print("\033[0m", end="")


print("Hello, World!")
with colored_output(31):
    print("Now in color!")
print("So cool.")
	

Другие материалы по теме

Путь Python Junior-а в 2017
17 лучших однострочников на Python
Программирование на Python: от новичка до профессионала

Комментарии

ВАКАНСИИ

Добавить вакансию
Разработчик C++
Москва, по итогам собеседования

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ