#python python... PYTHON 🔛 🚀
11 subscribers
914 photos
7 videos
158 files
1.54K links
Download Telegram
Зззнатокам Python хитрый вопрос!

Какой тип поставить у параметра field функции print_user_field, чтобы последняя строка при проверке типа показала ошибку? Перечислять второй раз поля User — нельзя, ибо делает возможным рассинхрон имён полей в классе и отдельном их перечислении.

Код скопировать можно здесь.

Вот так это делается на TS

А как на Python, м:)?

#IT #python #typescript #codebetter
Почему перечислять второй раз поля — плохо? Потому что возможна ситуация на скриншоте ⬆️ — поле name в User переименовалось в username, а в типах параметра field осталось name. Система проверки типов не покажет ошибку при вызове print_user_name(user, "name"), а хотелось бы ошибку увидеть, так как поля name уже нет.

Почему вынести эту проверку на переданное значение field в блок try/except — плохо? Потому что это уведёт ошибку в runtime, а надо минимизировать ошибки в рантайме, ошибки в рантайме = грустящие пользователи.

Систематических способа минимизировать ошибки в рантайме я знаю два, ТТ — как Тульский Токарев, только Типизация и Тесты.

Оба способа не гарантируют отсутствие ошибок, но позволяют вылавливать какое-то их количество на этапах до рантайма, то есть до пользователей. Чем лучше ТТ, тем меньше ошибок в рантайме.

Можно ли обойтись без типизации? Конечно, драматически увеличив количество тестов и проверок в коде, засорив код этими проверками.

Типизация помогает сократить количество тестов, потому что большой пласт ошибок выявляется на этапе проверки типов.

#python #it #codebetter
Media is too big
VIEW IN TELEGRAM
Работа с базами данных на Python

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

00:00 Введение
00:35 Создание файла базы данных
02:05 Создание таблицы
04:15 Запись данных в таблицу (метод execute)
06:20 Запись массива (метод executemany)
08:00 Как посмотреть содержимое БД
11:52 PRIMARY KEY
13:00 Типизация ячеек
16:25 Чтение из базы данных
21:57 Изменение значений
26:30 Удаление значений
28:20 Удаление таблицы

Смотреть это видео на youtube: youtu.be/siSRd4s7_ro
➡️ Задание от Сбербанка

В этой таблице безымянная частичная выгрузка перемещения пользователей по сайту. Один user_id — один пользователь. Расскажите нам всё, что сможете понять по такой выгрузке

Проведите когортный анализ (за основу для когорты можно взять неделю регистрации), подсчитайте ориентировочный срок жизни клиента/когорты оцените популярность отдельных материалов и форматов

Попробуйте определить общие паттерны у тех пользователей, кто перестал учиться на платформе, и у тех, кто продолжает учиться. Вероятно, на основе этих данных вы сможете сделать предложения по адаптации платформы? Каких данных вам не хватает, чтобы провести более детальный анализ?

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

⭐️ Датасет
🖥 Решение

@machinelearning_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Что такое фабрика декораторов?

Ответ

Это функция, которая возвращает декоратор. Например, вам нужен декоратор для проверки прав. Логика проверки одинакова, но прав может быть много. Чтобы не плодить копипасту, напишем фабрику декораторов.

from functools import wraps

def has_perm(perm):
def decorator(view):
@wraps(view)
def wrapper(request):
if perm in request.user.permissions:
return view(request)
else:
return HTTPRedirect('/login')
return wrapper
return decorator

@has_perm('view_user')
def users(request):
...


@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Что такое сериализация
Сериализация – это процесс сохранения объектов в двоичном или строковом виде для хранения, передачи и восстановления. Обратный процесс называется десериализацией. Термины-синонимы маршалинг/анмаршалинг

json.dumps / json.dump , json.loads / json.load
Функция dumps модуля json сохраняет JSON-представление объекта в строку. Функция dump – в текстовый файл. Функция loads модуля json загружает объект из строки. Функция load – из текстового файла.

Что делать если нужно сериализовать данные, которые не поддерживаются стандартным модулем json
Можно использовать pickle или расширить классы JSONEncoder и JSONDecoder.

pickle.dumps / pickle.dump, pickle.loads / pickle.load
Функции dump, dumps, load и loads модуля pickle аналогичны по своему предназначению соответствующим функциям модуля JSON, но работают с байтовыми строками и бинарными файлами.

Опциональный параметр protocol данных функций задаёт версию протокола. Последнюю версию протокола можно получить как константу pickle.HIGHEST_PROTOCOL, текущую версию по умолчанию – pickle.DEFAULT_PROTOCOL.

На момент написания данного текста существует пять версий протокола:

0 и 1 – это устаревшие версии, которые использовались в Python 2.2 и ниже;
2 – это основная версия протокола для Python 2;
3 – версия протокола, которая появилась в Python 3, стандартный протокол в Python 3 на текущий момент, не может быть десериализован в Python 2;
4 – версия протокола, появившаяся в Python 3.4, поддерживает очень большие по объёму памяти объекты, поддерживает большее количество типов объектов, добавлены некоторые оптимизации.
5 - версия протокола, появившаяся в Python 3.8. Он добавляет поддержку данных out-of-band и ускорение для in-band данных. PEP 574 более подробно описывает изменения.

@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Возможно ли множественное наследование? Что такое MRO?

Ответ
Да, можно указать более одного родителя в классе потомка.

MRO – method resolution order, порядок разрешения методов. Алгоритм, по которому следует искать метод в случае, если у класса два и более родителей. Алгоритм линеизирует граф наследования. Коротко можно описать так: ищи слева направо. Поэтому чем правее стоит класс, тем меньше у него приоритет при поиске метода.


Что такое миксины?

Ответ
Миксин (mix-in, анг. “примесь”), паттерн проектирования в ООП, когда в цепочку наследования добавляется небольшой класс-помощник. Например, есть класс

class NowMixin(object):
def now():
return datetime.datetime.utcnow()
Тогда любой класс, наследованный с этим миксином, будет иметь метод now().

@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Какие задачи хорошо параллелятся, какие плохо?

Те задачи, которые порождают долгий IO. Когда тред упирается в ожидание сокета или диска, интерпретатор бросает этот тред и стартует следующий. Это значит, не будет простоя из-за ожидания. Наоборот, если ходить в сеть в одном треде (в цикле), то каждый раз придется ждать ответа.

Однако, если затем в треде обрабатывает полученные данные, то выполнятся будет только он один. Это не только не даст прироста в скорости, но и замедлит программу из-за переключения на другие треды.

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

@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Напишите код, который будет рассчитывать угол между часовой и минутной стрелкой в заданное время. Данная задача покажет логическое мышление кандидата, и как быстро он сможет придумать решение.

Ответ на картинке

@python_job_interview
🖥 Что будет выведено после второго вызова append() в коде ниже?

>>> def append(list=[]):
... # добавление длины списка в список
... list.append(len(list))
... return list
...
>>> append(['a','b'])
['a', 'b', 2]
>>>
>>> append() # вызов без аргумента использует значение list по умолчанию []
[0]
>>>
>>> append() # Но что произойдёт при повторном вызове append без аргумента?


Ответ
Когда значением по умолчанию для аргумента функции является выражение, оно вычисляется только один раз, а не всегда при вызове функции. Таким образом, после того как аргумент list был инициализирован в пустой массив, последующие вызовы функции без аргументов продолжат использовать тот же самый массив, что был инициализирован изначально.

>>> append() # при первом вызове без аргумента используется значение по умолчанию []
[0]
>>> append() # но затем...
[0, 1]
>>> append() # последовательные вызовы расширяют список по умолчанию
[0, 1, 2]
>>> append() # и так продолжается...
[0, 1, 2, 3]


@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
В чем заключается смысл протокола итератора?
Любой объект в Питоне становится итератором только тогда, когда в него внедрен соответствующий протокол. Он включает 2 метода:

– iter() – возвращает сам себя, вызывается в самом начале. Позволяет пользоваться циклом for и выражением in»;
– next() – перебирает коллекцию по одному элементу и вызывает ошибку StopIteration, когда их не остается.

Пример:
---
>>> num_lst = [7, 10, 3]
>>> num_lst_iter = iter(num_lst)
>>> next(num_lst_iter)
7
>>> next(num_lst_iter)
10
>>> next(num_lst_iter)
3
>>> next(num_lst_iter)
StopIteration


Обозначенную последовательность чисел мы превратили в итератор с помощью функции iter(). После того как функция next() перебрала все значения, возникла ошибка StopIteration.

@python_job_interview
🖥 Расскажите про Метаклассы в Python

Метакласс это «штука», которая создаёт классы.

Мы создаём класс для того, чтобы создавать объекты, так? А классы являются объектами. Метакласс это то, что создаёт эти самые объекты. Они являются классами классов, можно представить это себе следующим образом:

MyClass = MetaClass()
MyObject = MyClass()

Мы уже видели, что type позволяет делать что-то в таком духе:

MyClass = type('MyClass', (), {})

Это потому что функция type на самом деле является метаклассом. type это метакласс, который Питон внутренне использует для создания всех классов.

@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 На собеседование в Google через челлендж Python #1

Как-то раз я искал в гугле что-то насчёт Python, как вдруг всплыло приглашение принять участие в испытании по программированию от Google (так называемое foo.bar challenge). Я не фанат состязаний по написанию кода или симуляций собеседований на Leetcode по ряду причин. Однако любопытство взяло верх, и я решил попробовать. Далее я расскажу, как подготовиться и пройти первое испытание.

➡️ Читать дальше

@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Где будет быстрее поиск, а где перебор и почему: dict, list, set, tuple

Поиск будет быстрее в dict и set, потому что это хэш-таблицы, доступ к элементу которых выполняется за O(1). Для list и tuple поиск будет выполняться в среднем за O(n).

Исключение работает только для очень маленьких списков длиной до 5 элементов. В этом случае интерпретатору будет быстрей пробежаться по списку, чем считать хеш.

В Python 2 методы словаря keys, values, items возвращают список. Тоесть перед итерацией по словарю (или сету) интерпретатор сначала создает новый список, что занимает дополнительное время и память, но после создания это уже обыкновенный список. Тоесть в Python 2 итерация по словарям и сетам выполняется дольше, за счет создания нового списка и копирования в него элементов.

В Python 3 эти методы создают объект-представление. Это определенно происходит быстрее чем создание нового списка в Python2. Но итерирование по такому представлению должно происходить немного дольше, чем по списку из-за того что данные в словарях хранятся разреженно (редко, негусто). В подтверждение вышесказанного (Python 3):

>>> l = list(range(1000000))
>>> d = dict.fromkeys(l)
>>> s = set(l)
>>> def iter_list():
... for i in l:
... pass
...
>>> def iter_dict():
... for i in d:
... pass
...
>>> def iter_set():
... for i in s:
... pass
...
>>> timeit.timeit(iter_list, number=1000)
6.727667486004066
>>> timeit.timeit(iter_dict, number=1000)
9.293120226997416
>>> timeit.timeit(iter_set, number=1000)
8.627948219014797


@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Как работает хэш-таблица

Хэш-таблица это разреженный массив (массив, в котором имеются незаполненные позиции). В стандартных англоязычных учебниках ячейки хэш-таблицы называются "bucket". В хэш-таблице dict каждому элементу соотвествует ячейка, содержащая два поля: ссылку на ключ и ссылку на значение элемента. Поскольку размер всех ячеек одинаков, доступ к отдельной ячейке производится по смещению.

Python стремится оставить не менее трети ячеек пустыми; если хэш-таблица становится чрезмерно заполненной, то она копируется в новый участок памяти, где есть место для большего числа ячеек.

Для помещения элемента в хэш-таблицу нужно первым делом вычислить хэш-значение ключа элемента. Это делает встроенная функция hash().

Для выборки значения с помощью выражения my_dict[search_key] Python обращается к функции hash(search_key), чтобы получить хэш-значение search_key, и использует несколько младших битов полученного числа как смещение ячейки относительно начала хэш-таблицы (сколько именно битов зависит от текущего размера таблицы). Если найденная ячейка пуста, возбуждается исключение KeyError. В противном случае в найденной ячейке есть какой-то элемент - пара ключ:значение - и тогда Python проверяет, верно ли то, что search_key == found_key. Если да, то элемент найден и возвращается found_value. Если же search_key и found_key не совпали, то имеет место коллизия хэширования. Для разрешения коллизии алгоритм берет различные биты хэш-значения, производит над ними определенные действия и использует результат как смещение другой ячейки.

Что такое коллизия
Когда хеш-функция возвращает один и тот же ответ для разных данных.

@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Почему использовать изменяемые объекты как параметры по-умолчанию плохо. Приведите пример плохого случая. Как исправить

Функция создается однажды при загрузке модуля. Именованные параметры и их дефолтные значения тоже создаются один раз и хранятся в одном из полей объекта-функции.

В нашем примере bar равен пустому списку. Список – изменяемая коллекция, поэтому значение bar может изменяться от вызова к вызову. Пример:

def foo(bar=[]):
bar.append(1)
return bar
foo()
>>> [1]
foo()
[1, 1]
foo()
>>> [1, 1, 1]


Хорошим тоном считается указывать параметру пустое неизменяемое значение, например 0, None, '', False. В теле функции проверять на заполненность и создавать новую коллекцию:

def foo(bar=None):
if bar is None:
bar = []
bar.append(1)
return bar
foo()
>>> [1]
foo()
>>> [1]
foo()
>>> [1]

Сказанное выше актуально в т.ч. для множеств и словарей.

@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Какие нюансы есть в использовании чисел как ключей

Числовые ключи в словарях подчиняются правилам сравнения чисел. Таким образом, int(1) и float(1.0) считаются одинаковым ключом. Однако из-за того, что значения типа float сохраняются приближенно, не рекомендуется использовать их в качестве ключей.

>>> {True: 'yes', 1: 'no', 1.0: 'maybe'}
{True: 'maybe'}


@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Расскажите про встроенная сортировка

В Python сортировка производится встроенной функцией sorted. Первым аргументом она принимает итерируемый объект. Это может быть список, кортеж, генератор, итератор и т.п. Возвращает отсортированный список.

>>> sorted([4, 2, 3, 1, 0])
[0, 1, 2, 3, 4]


>>> sorted(x * x for x in range(-5, 6))
[0, 1, 1, 4, 4, 9, 9, 16, 16, 25, 25]


Можно сортировать в обратном порядке:

>>> sorted([4, 2, 3, 1, 0], reverse=True)
[4, 3, 2, 1, 0]

Если сортируемые элементы – списки, словари или объекты, то воспользуемся параметром key. Мы передаем в key нечто вызываемое (имя функции, lambda и т.п), и при сортировки элементы сравниваются по результату вызова key на элементе. Результатом key должно быть число, строка или что-то другое сравнимое между собой.

📎 Пример. Сортировка списка строк по длине строки:

>>> sorted(["foo", "bazooka", "", "game"], key=len)
['', 'foo', 'game', 'bazooka']

📎 Пример. Сортировка списка кортежей по 0 или 1 элементу каждого.

>>> people = [("Bill", "Gates"), ("Tim", "Cook"), ("Donald", "Trump")]

>>> sorted(people, key=lambda t: t[0])
[('Bill', 'Gates'), ('Donald', 'Trump'), ('Tim', 'Cook')]

>>> sorted(people, key=lambda t: t[1])
[('Tim', 'Cook'), ('Bill', 'Gates'), ('Donald', 'Trump')]


Для этой же цели удобно использовать функцию operator.itemgetter:

>>> import operator
>>> sorted(people, key=operator.itemgetter(0))
[('Bill', 'Gates'), ('Donald', 'Trump'), ('Tim', 'Cook')]

Еще полезные функции из operator:
attrgetter(name) – для получение значения атрибута объекта с именем name
methodcaller(name[, args...]) – для получения результата вызова метода name у объекта. Опционально с аргументами args.
Вот пример кода с attrgetter и methodcaller.

Для списков (list) определен метод sort(), который модифицирует исходный список, выстраивая элемента по порядку.

>>> arr = [3, 4, 1, 2, 5, 6, 0]
>>> arr.sort()
>>> arr
[0, 1, 2, 3, 4, 5, 6]

Сортировка в Python – устойчива. Это значит, что порядок элементов с одинаковыми ключами будет сохранен в сортированной последовательности. Пример.

Внутри Python использует Timsort – гибридный алгоритм сортировки, сочетающий сортировку вставками и сортировку слиянием. Смысл в том, что в реальном мире часто встречаются частично отсортированные данные, на которых Timsort работает ощутимо быстрее прочих алгоритмов сортировки. Сложность по времени: O(n log n) в худшем случае и O(n) – в лучшем.

⚠️ CPython: не пытайтесь модифицировать сортируемый список во время сортировки. Эффект непредсказуем.

@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Что может являться ключом словаря. Что не может. Почему

Ключом словаря может быть любой хешируемый неизменяемый объект: число, строка, datetime, функция и даже модуль. Такие объекты имеют метод __hash__(), который однозначно сопоставляет объект с некоторым числом. По этому числу словарь ищет значение для ключа.

Списки, словари и множества изменяемы и не имеют метода хеширования. При подстановке их в словарь возникнет ошибка.

Хеш кортежа вычисляется рекурсивно по всем элементам. Так, кортеж

(1, (True, (42, ('hello', )))) состоит только из неизменяемых элементов, поэтому может быть ключом. Однако, такой кортеж

(1, (True, (42, ({'hello': 'world'}, )))) содержит глубоко внутри словарь, поэтому хеш не может быть рассчитан.

@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM