python and some backend notes(ru)
108 subscribers
5 photos
1 file
192 links
Личные заметки и ссылки на статьи по python и backend вопросам, но может кому-то тоже будет интересно
Download Telegram
В Python извлечение последнего элемента из списка занимает постоян-
ное время, но извлечение первого элемента является линейным по длине списка. В худшем случае
длина стека составляет O(n), что делает эту реализацию поиска в ширину O(nm), что намного хуже,
чем должно быть, O(n + m).

from collections import deque - позволяет использовать очередь, которая использует линейное время для доступа к элементам с обоих сторон
collections.counter

words = [
'look', 'into', 'my', 'eyes', 'look', 'into', 'my', 'eyes',
'the', 'eyes', 'the', 'eyes', 'the', 'eyes', 'not', 'around', 'the',
'eyes', "don't", 'look', 'around', 'the', 'eyes', 'look', 'into',
'my', 'eyes', "you're", 'under'
]
from collections import Counter
word_counts = Counter(words)
top_three = word_counts.most_common(3)
print(top_three)
# Выведет [('eyes', 8), ('the', 5), ('look', 4)]

Малоизвестная возможность экземпляров Counter состоит в том, что они могут быть легко скомбинированы с использованием разнообразных математических операций. Например:

>>> a = Counter(words)
>>> b = Counter(morewords)
>>> a
Counter({'eyes': 8, 'the': 5, 'look': 4, 'into': 3, 'my': 3, 'around': 2,
"you're": 1, "don't": 1, 'under': 1, 'not': 1})
>>> b
Counter({'eyes': 1, 'looking': 1, 'are': 1, 'in': 1, 'not': 1, 'you': 1,
'my': 1, 'why': 1})
>>> # Объединяем счетчики
>>> c = a + b
>>> c
Counter({'eyes': 9, 'the': 5, 'look': 4, 'my': 4, 'into': 3, 'not': 2,
'around': 2, "you're": 1, "don't": 1, 'in': 1, 'why': 1,
'looking': 1, 'are': 1, 'under': 1, 'you': 1})
>>> # Вычитаем счетчики
>>> d = a - b
>>> d
Counter({'eyes': 7, 'the': 5, 'look': 4, 'into': 3, 'my': 2, 'around': 2,
"you're": 1, "don't": 1, 'under': 1})
>>>

#algoritms #collections #counter
Сортировка списка словарей по общему ключу

rows = [
{'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
{'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
{'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
]

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

from operator import itemgetter
rows_by_uid = sorted(rows, key=itemgetter('uid'))
print(rows_by_uid)

>>>
[{'fname': 'John', 'uid': 1001, 'lname': 'Cleese'},
{'fname': 'David', 'uid': 1002, 'lname': 'Beazley'},
{'fname': 'Brian', 'uid': 1003, 'lname': 'Jones'},
{'fname': 'Big', 'uid': 1004, 'lname': 'Jones'}]

аналогично:

rows_by_fname = sorted(rows, key=lambda r: r['fname'])

но itemgetter работает быстрее. operator.attgetter() работает с аттрибутами обьектов

#algoritms #sorting #operator #itemgetter #attgetter
Группирование записей на основе полей

Функция itertools.groupby()

rows = [
{'address': 'CLARK', 'date': '07/01/2012'},
{'address': 'CLARK', 'date': '07/04/2012'},
{'address': '58TH', 'date': '07/02/2012'},
{'address': 'CLARK', 'date': '07/03/2012'},
{'address': 'RAVENSWOOD', 'date': '07/02/2012'},
{'address': 'ADDISON', 'date': '07/02/2012'},
{'address': 'BROADWAY', 'date': '07/01/2012'},
{'address': 'GRANVILLE', 'date': '07/04/2012'},
]


from operator import itemgetter
from itertools import groupby

# Сначала сортируем по нужным полям
rows.sort(key=itemgetter('date'))

# Итерируем в группах
for date, items in groupby(rows, key=itemgetter('date')):
print(date)
for i in items:
print(' ', i)
>>>

07/01/2012
{'date': '07/01/2012', 'address': 'CLARK'}
{'date': '07/01/2012', 'address': 'BROADWAY'}
07/02/2012
{'date': '07/02/2012', 'address': '58TH'}
{'date': '07/02/2012', 'address': 'RAVENSWOOD'}
{'date': '07/02/2012', 'address': 'ADDISON'}
07/03/2012
{'date': '07/03/2012', 'address': 'CLARK'}
07/04/2012
{'date': '07/04/2012', 'address': 'CLARK'}
{'date': '07/04/2012', 'address': 'GRANVILLE'}

#algoritms #itertools #groupby
Удаление дубликатов из последовательности
с сохранением порядка элементов

def dedupe(items):
seen = set()
for item in items:
if item not in seen:
yield item
seen.add(item)

Множество не сохраняет какой бы то ни было порядок, поэтому результат будет перемешан.

#algoritms #generators
оператор nonlocal. from python 3+
Логика его написания примерно такая же, как и у global. Однако у nonlocal есть особенность. Nonlocal используется чаще всего во вложенных функциях, когда мы хотим дать интерпретатору понять, что для вложенной функции определенная переменная не является локальной, но она и не является глобальной в общем смысле.

def get_candy():
candy = 5
def increment_candy():
nonlocal candy
candy += 1
return candy
return increment_candy

result = get_candy()()
print('Всего {} конфет.'.format(result))
>>>
Всего 6 конфет.

#operator #nonlocal
Реализация цикла for с помощью функции и цикла while

def for_loop(iterable, loop_body_func):
iterator = iter(iterable)
next_element_exist = True
while next_element_exist:
try:
element_from_iterator = next(iterator)
except StopIteration:
next_element_exist = False
else:
loop_body_func(element_from_iterator)

Здесь использовали конструкцию try-else. Она позволяет выполнять код, если исключения не возникло, и код был выполнен успешно.

#algoritms #iterator #exceptions
* Итерируемый объект — это что-то, что можно итерировать.
* Итератор — это сущность порождаемая функцией iter, с помощью которой происходит итерирование итерируемого объекта.
* Итератор не имеет индексов и может быть использован только один раз.
* Итератор имеет методы __next__ __iter__, а также вызывает исключение StopIteration при невозможности получения следующего элемента
* В случае, если мы передаём в iter итератор, то получаем тот же самый итератор

class InfiniteSquaring:
"""Класс обеспечивает бесконечное последовательное возведение в квадрат заданного числа."""
def __init__(self, initial_number):
# Здесь хранится промежуточное значение
self.number_to_square = initial_number

def __next__(self):
# Здесь мы обновляем значение и возвращаем результат
self.number_to_square = self.number_to_square ** 2
return self.number_to_square

def __iter__(self):
"""Этот метод позволяет при передаче объекта функции iter возвращать самого себя, тем самым в точности реализуя протокол итератора."""
return self

#iterrator #iter #next
Кэширование (мемоизация) с помощью lru_cache

import functools
import time

# кэширование до 12 различных результатов
@functools.lru_cache(maxsize=12)
def slow_func(x):
time.sleep(2) # Имитируем длительные вычисления
return x

slow_func(1) # ... ждём 2 секунды до возврата результата
slow_func(1) # результат уже кэширован - он возвращается немедленно!

slow_func(3) # ... опять ждём 2 секунды до возврата результата

#lru_cache #decorator
https://t.me/pythonbooksarchive - архив книг по python

#books
Никогда не стоит использовать f-strings для логгирования в python, такие строки будут выполняться вне зависимости от того, должна ли быть вызвана функция логгирования на текущем уровне. Стоит использовать старый формат для строк.
logger.info('Requests sent: %s success: %s errors: %s', self.request_sent, self.success, self.errors)

#logging #f_strings