#python python... PYTHON 🔛 🚀
11 subscribers
914 photos
7 videos
158 files
1.54K links
Download 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
🖥 Что такое args, kwargs. В каких случаях они требуются?

Выражения *args и **kwargs объявляют в сигнатуре функции. Они означают, что внутри функции будут доступны переменные с именами args и kwargs (без звездочек). Можно использовать другие имена, но это считается дурным тоном.

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

Важно: если в функцию не передано никаких параметров, переменные будут соответственно равны пустому кортежу и пустому словарю, а не None.

Пожалуйста, не путайте кортеж со списком.

@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Что такое лямбды. Каковы их особенности
Это анонимные функции. Они не резервируют имени в пространстве имен. Лямбды часто передают в функции map, reduce, filter.

Лямбды в Питоне могут состоять только из одного выражения. Используя синтаксис скобок, можно оформить тело лямбды в несколько строк.

Использовать точку с запятой для разделения операторов нельзя.

Допустимы ли следующие выражения
nope = lambda: pass
riser = lambda x: raise Exception(x)

Нет, при загрузке модуля выскочит исключение SyntaxError. В теле лямбды может быть только выражение. pass и raise являются операторами.

@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Как передаются значения аргументов в функцию или метод

Интересности и полезности python. Часть 3
В таких языках как C++ есть переменные, хранящиеся на стеке и в динамической памяти. При вызове функции мы помещаем все аргументы на стек, после чего передаём управление функции. Она знает размеры и смещения переменных на стеке, соответственно может их правильно интерпретировать. При этом у нас есть два варианта: скопировать на стек память переменной или положить ссылку на объект в динамической памяти (или на более высоких уровнях стека). Очевидно, что при изменении значений на стеке функции, значения в динамической памяти не поменяются, а при изменении области памяти по ссылке, мы модифицируем общую память, соответственно все ссылки на эту же область памяти «увидят» новое значение.

В python отказались от подобного механизма, заменой служит механизм связывания (assignment) имени переменной с объектом, например при создании переменной: var = "john"

Интерпретатор создаёт объект «john» и «имя» var, а затем связывает объект с данным именем. При вызове функции, новых объектов не создаётся, вместо этого в её области видимости создаётся имя, которое связывается с существующим объектом. Но в python есть изменяемые и неизменяемые типы. К первым, например, относятся числа: при арифметических операциях существующие объекты не меняются, а создаётся новый объект, с которым потом связывается существующее имя. Если же со старым объектом после этого не связано ни одного имени, оно будет удалено с помощью механизма подсчёта ссылок. Если же имя связано с переменной изменяемого типа, то при операциях с ней изменяется память объекта, соответственно все имена, связанные с данной областью памяти «увидят» изменения.

@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Расскажите про замыкания. Какая проблема возникает при создание нескольких функций внутри одного контекста?

Когда вы определяете функцию внутри другой функции и используете локальные переменные внешней функции во вложенной, вы создаете замыкание. Время жизни этих переменных "продляется" в особой области видимости enclosing даже после завершения работы внешней функции. Пример: make_adder возвращает функцию-прибавлятор. Объект из переменной a будет жить и работать даже после выхода из make_adder:

def make_adder(a):
def adder(x):
return a + x
return adder

plus_5 = make_adder(5)
print(plus_5(3)) # 8


Здесь я хочу коснуться одной популярной проблемы. Дело в том, что если мы создадим несколько функций внутри одного контекста, то они будут разделять одну область видимости enclosing. Рассмотрим пример создания трех функций в цикле:

def make_adders():
adders = []
for a in range(3):
def adder(x):
return a + x
adders.append(adder)
return adders

adders = make_adders()
for adder in adders:
print(adder(2)) # 4 4 4


Вместо функций прибавляющих разные числа от 0 до 2, мы получили 3 одинаковых функции, потому что внутри себя они поддерживают ссылку на одну и ту же переменную a, значение которой останется равным 2 после выполнения всего цикла целиком.

Есть простой прием, помогающий "зафиксировать" значения переменной в моменте: достаточно добавить во вложенную функцию дополнительный аргумент со значением по умолчанию, равным нужной переменной a=a:

def make_adders():
adders = []
for a in range(3):
def adder(x, a=a): # FIX!
return a + x
adders.append(adder)
return adders

adders = make_adders()
for adder in adders:
print(adder(2)) # 2 3 4


Еще лучше переименовать аргумент, чтобы избежать конфликтов имен и замечаний IDE, например, так:

def adder(x, that_a=a): # FIX!
return that_a + x


@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Что такое итерабельный объект?

Итерабельный объект (в оригинальной терминологии – «iterable») – это объект, который может возвращать значения по одному за раз. Примеры: все контейнеры и последовательности (списки, строки и т.д.), файлы, а также экземпляры любых классов, в которых определён метод __iter__() или __getitem__(). Итерабельные объекты могут быть использованы внутри цикла for, а также во многих других случаях, когда ожидается последовательность (функции sum(), zip(), map() и т.д.).

Подробнее:

Рассмотрим итерируемый объект (Iterable). В стандартной библиотеке он объявлен как абстрактный класс collections.abc.Iterable:

class Iterable(metaclass=ABCMeta):

__slots__ = ()

@abstractmethod
def __iter__(self):
while False:
yield None

@classmethod
def __subclasshook__(cls, C):
if cls is Iterable:
return _check_methods(C, "__iter__")
return NotImplemented
У него есть абстрактный метод __iter__ который должен вернуть объект итератора. И метод __subclasshook__ который проверяет наличие у класса метод __iter__. Таким образом, получается, что итерируемый объект это любой объект который реализует метод __iter__

class SomeIterable1(collections.abc.Iterable):
def __iter__(self):
pass

class SomeIterable2:
def __iter__(self):
pass

print(isinstance(SomeIterable1(), collections.abc.Iterable))
# True
print(isinstance(SomeIterable2(), collections.abc.Iterable))
# True
Но есть один момент, это функция iter(). Именно эту функцией использует например цикл for для получения итератора. Функция iter() в первую очередь для получения итератора из объекта, вызывает его метод __iter__. Если метод не реализован, то она проверяет наличие метода __getitem__ и если он реализован, то на его основе создается итератор. __getitem__ должен принимать индекс с нуля. Если не реализован ни один из этих методов, тогда будет вызвано исключение TypeError.

from string import ascii_letters

class SomeIterable3:
def __getitem__(self, key):
return ascii_letters[key]

for item in SomeIterable3():
print(item)


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