Basic Python
Что за язык Python?
Высокоуровневый с динамической строгой типизацией.
Python не разрешит сложить число 1
и строку '7'
, потому ,что это значения разных типов. Нужно сначала либо сделать строку числом, либо число строкой.
Динамически типизированные языки не требуют указывать тип, но и не определяют его сами.
Почему он медленный?
- Интерпретируемость
- Нету JIT-complier из коробки
- GIL
mutable / immutable типы данных
bool, int, float, tuple, str, frozenset, nonetype - immutable list, set, dict - mutable
Нужны оба типа для того, чтобы было меньше памяти использовано или же для дизайна.
Bounded and unbounded методы?
bounded — это тот метод, где нужно вызывать через объект класса и в методе есть self unbounded — это тот метод, которые не закреплены перед объектом и могут свободно вызываться без него (по факту staticmethod)
При измени значения int будет ли меняться id?
Да будет, потому что int — это неизменяемый тип данных
Что может быть в качестве ключа словаря?
Могут быть: целые и действительные числа, строки, кортежи. Не может быть set, list, но может быть frozenset.
args & kwargs
*args
(неограниченное количество позиционных) - e.g. tuple, **kwargs
(неограниченное количество именованных) - e.g. dict
Грубо говоря, *args
складывает все аргументы (которые даже не имеют названий переменных, а только значения) в tuple, а **kwargs
требует, чтобы мы передавали название переменной в которую хотим сложить словарь
**kwargs
— это аргументы, передаваемые в вызов при помощи имени (идентификатора), либо словаря с его распаковкой при помощи **
.
*args
— это аргументы, передаваемые в вызов в определённой последовательности (на определённых позициях), без указания их имён.
Замыкание (closure)
Замыкание (closure) — функция, которая находится внутри другой функции и ссылается на переменные объявленные в теле внешней функции (свободные переменные).
Можем использовать: а) когда мы должны спрятать данные и не использовать глобальную переменную б) иногда использует место класса
У всех объектов будет приватный атрибут closure
, которые возвращает кортеж из cell objects, если это функция замыкания.
Даже, если мы удалим внешнюю функцию, то вызывая объект функции все будет работать, несмотря на то, что конструкция стерта.
Декоратор с прокидыванием переменной
functools.wraps() — функцию, которая помогает сделать декорируемую функцию похожей на исходную, делая такие вещи, как сохранение doctstring исходной функции.
Часто используется при создании декоратора.
Итератор и генератор
Итератор — это объект, который возвращает свои элементы по одному за раз или же это итер. объект который содержит исчисляемое число значений, по которому можно итерироваться.
В python это реализовано через методы iter и next
iter
возвращает ссылку на итераторnext
возвращает следующий элемент
Генератор — это объект, который сразу при создании не вычисляет значения всех своих элементов. ДЕРЖИТ ОДИН. Или другими словами, это итератор элементы которого можно итерировать только один раз.
Преимущества yield:
• экономия памяти • не останавливается, а возобновляет работу
Как создать:
• Выражение-генератор можно вызывать через (i for …)
• В функции вместо return
использовать yield
Итератор не является генератором! Но любой генератор является итератором.
range
не является генератором и там есть операторin
и там есть спец магические методы
Что такое coroutine?
Корутина — это генератор, к которому добавлена возможность послать данные через метод send
. То есть их можно запустить, остановить и перезапустить.
Что такое future?
Что такое дескрипторы?
Дескриптор – это механизм, где __get__()
, __set__()
и __delete__()
перегружены, то есть смена поведения обновления, получения и удаления атрибута класса.
collections
Модуль, в котором содержутся: namedtuple, Counter, defaultdict, OrderedDict
.
PYTHOPATH
Переменная среды PYTHONPATH используется в Python для указания списка каталогов, из которых можно импортировать модули. При запуске можно проверить переменную sys.path
, чтобы узнать, по каким каталогам будет выполняться поиск при импорте чего-либо.
Чтобы задать эту переменную из командной строки, используйте: set PYTHONPATH=list;of;paths
.
Как понять хешируемый ли объект
Объект называется хешируемым, если он имеет хеш-значение (целое число), которое никогда не изменяется на протяжении его жизненного цикла и возвращается методом __hash__()
, и может сравниваться с другими объектами (реализует метод __eq__()
). Равные хешируемые объекты должны иметь равные хеш-значения. Все стандартные неизменяемые объекты хешируемые. Все стандартные изменяемые объекты не хешируемые.
Как кодировать и декодировать строки
Кодировать – перевести Юникод в байтовую строку. Вызвать метод .encode()
у строки.
Декодировать – восстановить строку из цепочки байт. Вызвать метод .decode()
у объекта str
или bytes
(версии Питона 2 и 3 соответственно).
В обоих случаях явно передавать кодировку, иначе будет использована та, что определена в системе по умолчанию. Быть готовым поймать исключения UnicodeEncodeError
, UnicodeDecodeError
.
Какие виды строк бывают в питоне
Зависит от версии Питона. Во второй ветке два типа: однобайтные строки и Юникод представлены классами str и unicode соответственно. В третьем Питоне есть один вид строк str, который представляет собой Юникод. Однобайтных строк нет, вместо них есть тип bytes, то есть цепочка байт.
Какие нюансы есть в использовании чисел как ключей
Числовые ключи в словарях подчиняются правилам сравнения чисел. Таким образом, int(1)
и float(1.0)
считаются одинаковым ключом. Однако из-за того, что значения типа float сохраняются приближенно, не рекомендуется использовать их в качестве ключей.
Memory Management
Как создается переменная?
- Сначала создается объект со значением переменной
- Переменная начинает ссылаться на него
Memory consumption
Python не освобождает всю память обратно операционной системе как только он удаляет какой либо объект. Вместо этого, он использует дополнительный менеджер памяти, предназначенный для маленьких объектов (размер которых меньше чем 512 байт). Для работы с такими объектами он выделяет большие блоки памяти, в которых в дальнейшем будет хранится множество маленьких объектов.
Как только один из маленьких объект удаляется — память из под него не переходит операционной системе, Python оставляет её для новых объектов с таким же размером. Если в одном из выделенных блоков памяти не осталось объектов, то Python может высвободить его операционной системе.
Garbage collector
Стандартный интерпретатор питона (CPython) использует сразу два алгоритма:
– подсчет ссылок – generational garbage collector (далее GC)
1. Алгоритм подсчета ссылок. Объекты удаляются как только на них больше нет ссылок. Он постоянно работает в режиме реального времени. Не нужен объект – убрали.
Алгоритм очень простой и эффективный, но у него есть один большой недостаток. Он не умеет определять циклические ссылки. Именно из-за этого, в питоне существует дополнительный сборщик, именуемый GC, который следит за объектами с потенциальными циклическими ссылками.
Минусы | Плюсы |
---|---|
циклические ссылки | объекты удаляются сразу как только они не нужны |
блокирование потоков | |
дополнительные накладные расходы на память и cpu |
Проверить текущее кол-во ссылок можно через sys.getrefcount(foo))
.
2. GC не работает в режиме реального времени и запускается периодически. Сборщик мусора разделяет все объекты на 3 поколения (генерации). Новые объекты попадают в первое поколение. Если новый объект выживает процесс сборки мусора, то он перемещается в следующее поколение. Чем выше поколение, тем реже оно сканируется на мусор.
Чтобы узнать порог отсеивания: gc.get_threshold()
→ (700, 10, 10).
Useful libs:
Какой метод разрешения коллизии используется в Python?
В Python используется метод открытой адресации.
More about collisions → Computer Science
OOP
Property
Обеспечивает интерфейс для атрибутов экземпляра класса. Он инкапсулирует атрибуты экземпляров и позволяет устанавливать setter, getter, deleter.
Classmethod vs Staticmethod
classmethod | staticmethod |
---|---|
Принимает cls как первый аргумент. | Не принимает дополнительных параметров. |
можно обращаться только к атрибутам класса, но не объекта. | Через этот метод нельзя обратиться ни к объектам, ни к методам класса. |
Используем тогда, когда нужен доступ только к методам класса. Может быть использован как фабрика-метод, который будет возвращать объект класса. | Используем тогда, когда ни используется объект класса, ни атрибуты класса. Utility-type методы, которые ничего не знают о классе. |
Dataclass
Используем, когда хотим хранить какие-то данные внутри класса. Следующие методы будут автоматически сгенерированы и код будет короче:
init
repr
eq
MRO
Это набор правил, по которому формируется схема наследования.
В python 2 алгоритм поиска в глубину: от текущего класса к родительскому и выше В python 3 алгоритм поиска в ширину: текущий класс и по всем его родителям
Можно вызвать через Class.mro()
, чтобы увидеть схему наследования.
Diamond problem
Коренной класс А
имеет детей B
& C
, а D
наследуется от B
& C
.
Mixin
Это небольшие классы, которые используются для того, чтобы дать дополнительный функционал другому классу. Например, полезно, когда:**
- хотим добавить множество функций для класса
- хотим использовать конкретную функцию во множестве разных классов
При создании класса в компании дописываем Mixin.
Metaclasses
Метаклассы — шаблоны для создания классов. Объекты создаются классом, а классы создаются метаклассом. Методы: prepare
(подготавливает данные), new
(создает класс), init
(инициализацию), call
(создание класса)
Например, type
— это метакласс.
Зачем нужен метод super?
Позволяет обращаться к классу-родителю. Основное ее применение и польза – получения доступа из класса наследника к методам класса-родителя в том случае, если наследник переопределил эти методы.
Например, мы хотим внести какие-то изменения в дочернем классе не вызывая материнский объект. Вместо этого мы пишем super.our_method()
Чаще всего в init
используется.
Что такое магические методы? Какие магические методы есть и для чего используются?
Это специальные методы, с помощью которых вы можете добавить в ваши классы «магию». Они всегда обрамлены двумя нижними подчеркиваниями.
Конструирование и инициализация
__new__(cls, [...)
— это первый метод, который будет вызван при инициализации объекта. Он принимает в качестве параметров класс и потом любые другие аргументы, которые будут переданы в__init__
; переписывается для кастомизации создании класса и возвращает инстанс класса__init__(self, [...)
— инициализатор класса.__del__
— это его деструктор
Магические методы сравнения
• __eq__(self, other)
Определяет поведение оператора равенства, ==
.
Числовые магические методы
• __abs__(self)
Определяет поведение для встроенной функции abs()
.
• __round__(self, n)
Определяет поведение для встроенной функции round()
. n
это число знаков после запятой, до которого округлить.
Представление своих классов
• __str__(self)
Определяет поведение функции str()
, вызванной для экземпляра вашего класса.
• __repr__(self)
делает то же самое, что и __str__(self)
, но главное отличие от str()
в целевой аудитории. repr()
больше предназначен для машинно-ориентированного вывода (более того, это часто должен быть валидный код на Питоне), а str()
предназначен для чтения людьми.
• __dir__(self)
Определяет поведение функции dir()
, вызванной на экземпляре вашего класса. Этот метод должен возвращать пользователю список атрибутов.
Зачем нужен метод super?
Позволяет обращаться к классу-родителю. Основное ее применение и польза – получения доступа из класса наследника к методам класса-родителя в том случае, если наследник переопределил эти методы.
Например, мы хотим внести какие-то изменения в дочернем классе не вызывая материнский объект. Вместо этого мы пишем super.our_method()
Чаще всего в init
используется.
Модификаторы доступа в python
__private
существует только внутри класса, даже с наследованием невозможно получить
_protected
можно пронаследовать
Через protected доступ будет в текущем классе и в дочерних классах, но снаружи вызвать его будет нельзя. Отличие в том, что через private доступа не будет и будет кидать AttributeError
, а в protected доступ все еще будет.
По факту вызвать все равно можно даже private через objectclass._Class__privateatr
Concurrency
GIL – зачем нужен?
GIL является самым простым способом избежать конфликтов при одновременном обращении разных потоков к одним и тем же участкам памяти. Когда один поток захватывает его, GIL, работая по принципу мьютекса, блокирует остальные. Нет параллельных потоков — нет конфликтов при обращении к разделяемым объектам.
Thread
Пото́к — наименьшая единица обработки, исполнение которой может быть назначено ядром операционной системы. Поток выполнения находится внутри процесса.
Mutex
A mutual exclusion lock or mutex lock is a synchronization primitive intended to prevent a race condition. Mutex следит за тем, чтобы выполнялся только один тред.
threading.Lock()
- mutex in Python
Semaphore
Инструмент, который ограничивает количество потоков, которое может быть использовано Lock() объектом. По факту это расширение мьютекса.
То есть, если в семафоре стоит “1”
, то он работает также как и мьютекс.
Можно также использовать семафору для того, чтобы ограничить:
- кол-во калькуляций
- кол-во открытых сокетов
- кол-во операций I/O
Race condition
Два треда запускают один и тот же код и могут получить доступ, либо изменять один и тот же ресурс, оставляя ресурс в непонятном виде.
Deadlock
A deadlock is a concurrency failure mode where a thread or threads wait for a condition that never occurs.
Например:
- поток A waits for B and B waits for A
- поток ждет сам себя
- неправильное расположение
acquire
среди потоков - после
acquire
потока-1 происходит exception и доrelease
не доходит
Чтобы избежать блокировок:
- Использовать контексные менеджеры
- Использовать timeout
- Всегда acquire locks в верном порядке
Reference:
How to Identify a Deadlock in Python
Сложность операций в коллекциях
list
Operation | Average Case | http://en.wikipedia.org/wiki/Amortized_analysis |
---|---|---|
Copy | O(n) | O(n) |
Append[1] | O(1) | O(1) |
Pop last | O(1) | O(1) |
Pop intermediate[2] | O(n) | O(n) |
Insert | O(n) | O(n) |
Get Item | O(1) | O(1) |
Set Item | O(1) | O(1) |
Delete Item | O(n) | O(n) |
Iteration | O(n) | O(n) |
Get Slice | O(k) | O(k) |
Del Slice | O(n) | O(n) |
Set Slice | O(k+n) | O(k+n) |
Extend[1] | O(k) | O(k) |
http://svn.python.org/projects/python/trunk/Objects/listsort.txt | O(n log n) | O(n log n) |
Multiply | O(nk) | O(nk) |
x in s | O(n) | |
min(s), max(s) | O(n) | |
Get Length | O(1) | O(1) |
collections.deque
represented internally as a doubly linked list.
Operation | Average Case | Am. Worst Case |
---|---|---|
Copy | O(n) | O(n) |
append | O(1) | O(1) |
appendleft | O(1) | O(1) |
pop | O(1) | O(1) |
popleft | O(1) | O(1) |
extend | O(k) | O(k) |
extendleft | O(k) | O(k) |
rotate | O(k) | O(k) |
remove | O(n) | O(n) |
Get Length | O(1) | O(1) |
set
Operation | Average case | Worst Case |
---|---|---|
x in s | O(1) | O(n) |
Union s | t | https://wiki.python.org/moin/TimeComplexity_%28SetCode%29 |
Intersection s&t | O(min(len(s), len(t))) | O(len(s) * len(t)) |
Multiple intersection s1&s2&..&sn | (n-1)*O(l) where l is max(len(s1),..,len(sn)) | |
Difference s-t | O(len(s)) | |
s.difference_update(t) | O(len(t)) | |
Symmetric Difference s^t | O(len(s)) | O(len(s) * len(t)) |
s.symmetric_difference_update(t) | O(len(t)) | O(len(t) * len(s)) |
dict
Operation | Average Case | Amortized Worst Case |
---|---|---|
k in d | O(1) | O(n) |
Copy[3] | O(n) | O(n) |
Get Item | O(1) | O(n) |
Set Item[1] | O(1) | O(n) |
Delete Item | O(1) | O(n) |
Iteration[3] | O(n) | O(n) |
Reference: TimeComplexity - Python Wiki