Объясните, как работает функция reduce
Ответ
Это может быть сложновато сразу понять, пока вы не используете ее несколько раз.
reduce принимает функцию и последовательность — и проходит по этой последовательности. На каждой итерации в функцию передаются как текущий элемент, так и выходные данные предыдущего элемента. В конце концов, возвращается одно значение .
Возвращается 11, что является суммой 1+2+3+5.
@python_job_interview
Ответ
Это может быть сложновато сразу понять, пока вы не используете ее несколько раз.
reduce принимает функцию и последовательность — и проходит по этой последовательности. На каждой итерации в функцию передаются как текущий элемент, так и выходные данные предыдущего элемента. В конце концов, возвращается одно значение .
from functools import reduce
def add_three(x,y):
return x + y
li = [1,2,3,5]
reduce(add_three, li)
#=> 11
Возвращается 11, что является суммой 1+2+3+5.
@python_job_interview
Что такое _slots_ в Python ?
По умолчанию классы используют словарь для хранения атрибутов — это позволяет модифицировать набор атрибутов объекта прямо в ходе исполнения программы. Однако такой подход оказывается затратным для объектов, набор атрибутов которых невелик и/или ограничен. Это становится особенно заметно, когда создаётся большое количество экземпляров.
Поведение по умолчанию можно изменить, задав slots при определении класса. В slots могут быть перечислены атрибуты для значений которых требуется зарезервировать место (с точки зрения CPython в объекте класса резервируется место для массива указателей на Python-объекты). При этом ни dict, ни weakref для экземпляров автоматически созданы не будут (даже если в качестве значения строки указать пустую строку).
В качестве значения slots может быть указана строка, объект поддерживающий итерирование, или последовательность строк с именами атрибутов, использующихся экземплярами.
Слоты реализуются при помощи создания дескриптора для каждого из перечисленных атрибутов.
Попытки присвоить экземпляру атрибут, который не был перечислен в slots будет поднято исключение AttributeError.
2.3 Если требуется динамическое назначение атрибутов, следует указать в перечислении слотов '__dict__'.
Не имея атрибута weakref, экземпляры классов со slots не поддерживают слабые ссылки на себя.
2.3 Если требуется поддержка слабых ссылок, следует указать в перечислении слотов '__weakref__'.
Область действия слотов ограничено классом, в котором они определены, поэтому наследники (если конечно они не определили собственные слоты) будут иметь dict.
Если наследники тоже определяют слоты, то в перечислении должны содержаться лишь дополнительные. В последующих версиях возможно будет реализована проверка на совпадение имён.
Непустой slots не может быть использован для классов, наследующихся от встроенных типов переменной длины, например long, str и кортеж. При попытке сделать это будет поднято исключение TypeError.
Слот может принимать перечисления с «нестроками». Например, могут использоваться отображения, однако в будущих версиях значения по ключам могут быть наделены неким определённым смыслом.
2.6 Если назначается class, следует проследить, что для обоих классов определены одинаковые слоты.
@python_job_interview
Ответ
Позволяет снизить объём памяти, потребляемой экземплярами класса, ограничивая количество атрибутов ими поддерживаемых.По умолчанию классы используют словарь для хранения атрибутов — это позволяет модифицировать набор атрибутов объекта прямо в ходе исполнения программы. Однако такой подход оказывается затратным для объектов, набор атрибутов которых невелик и/или ограничен. Это становится особенно заметно, когда создаётся большое количество экземпляров.
Поведение по умолчанию можно изменить, задав slots при определении класса. В slots могут быть перечислены атрибуты для значений которых требуется зарезервировать место (с точки зрения CPython в объекте класса резервируется место для массива указателей на Python-объекты). При этом ни dict, ни weakref для экземпляров автоматически созданы не будут (даже если в качестве значения строки указать пустую строку).
В качестве значения slots может быть указана строка, объект поддерживающий итерирование, или последовательность строк с именами атрибутов, использующихся экземплярами.
Слоты реализуются при помощи создания дескриптора для каждого из перечисленных атрибутов.
class Ordinary(object):
"""Экземпляры этого класса могут дополняться атрибутами
во время исполнения.
"""
class WithSlots(object):
__slots__ = 'static_attr'
a = Ordinary()
b = WithSlots()
a.__dict__ # {}
b.__dict__ # AttributeError
a.__weakref__ # None
b.__weakref__ # AttributeError
a.static_attr = 1
b.static_attr = 1
a.dynamic_attr = 2
b.dynamic_attr = 2 # AttributeError
Попытки присвоить экземпляру атрибут, который не был перечислен в slots будет поднято исключение AttributeError.
2.3 Если требуется динамическое назначение атрибутов, следует указать в перечислении слотов '__dict__'.
Не имея атрибута weakref, экземпляры классов со slots не поддерживают слабые ссылки на себя.
2.3 Если требуется поддержка слабых ссылок, следует указать в перечислении слотов '__weakref__'.
Область действия слотов ограничено классом, в котором они определены, поэтому наследники (если конечно они не определили собственные слоты) будут иметь dict.
Если наследники тоже определяют слоты, то в перечислении должны содержаться лишь дополнительные. В последующих версиях возможно будет реализована проверка на совпадение имён.
Непустой slots не может быть использован для классов, наследующихся от встроенных типов переменной длины, например long, str и кортеж. При попытке сделать это будет поднято исключение TypeError.
Слот может принимать перечисления с «нестроками». Например, могут использоваться отображения, однако в будущих версиях значения по ключам могут быть наделены неким определённым смыслом.
2.6 Если назначается class, следует проследить, что для обоих классов определены одинаковые слоты.
@python_job_interview
Расскажите о концепции распределенной архитектуры
Ответ
В больших системах, которые обрабатывают миллионы событий в день, некоторые вещи просто по определению обязаны пойти не по плану. Вот почему прежде, чем погружаться в планирование системы, нужно сделать самый важный шаг — принять решение о том, что для нас означает «здоровая» система. Степень «здоровья» должна быть чем-то таким, что на самом деле можно измерить. Общепринятым способом измерения «здоровья» системы являются SLA (service level agreements). Вот некоторые из самых распространённых видов SLA:
Доступность (Availability): процент времени, который сервис является работоспособным. Пусть существует искушение достичь 100% доступности, достижение этого результата может оказаться по-настоящему сложным занятием, да ещё вдобавок и весьма дорогостоящим. Даже крупные и критичные системы вроде сети карт VISA, Gmail или интернет-провайдеров не имеют 100% доступности — за годы они накопят секунды, минуты или часы, проведённые в даунтайме. Для многих систем, доступность в четыре девятки (99.99%, или примерно 50 минут даунтайма в год) считается высокой доступностью. Для того, чтобы добраться до этого уровня, придётся изрядно попотеть.
Точность (Accuracy): является ли допустимой потеря данных или их неточность? Если да, то какой процент является приемлимым? Для системы платежей, над которой я работал, этот показатель должен был составлять 100%, поскольку данные терять было нельзя.
Пропускная способность/мощность (Capacity): какую нагрузку должна выдерживать система? Этот показатель обычно выражается в запросах в секунду.
Задержка (Latency): за какое время система должна отвечать? За какое время должны быть обслужены 95% и 99% запросов? В подобных системах обычно многие из запросов являются «шумом», поэтому задержки p95 и p99 находят более практическое применение в реальном мире.
Горизонтальное и вертикальное масштабирование
По мере роста бизнеса, который использует нашу свежесозданную систему, нагрузка на неё будет лишь увеличиваться. В определенный момент, существующая установка будет неспособна выдержать дальнейшее увеличение нагрузки, и нам потребуется увеличить допустимую нагрузку. Две общепринятые стратегии масштабирования — это вертикальное или горизонтальное масштабирование.
Горизонтальное масштабирование заключается в добавлении большего количества машин (или узлов) в систему для увеличения пропускной способности (capacity). Горизонтальное масштабирование — это самый популярный способ масштабирования распределённых систем.
Вертикальное масштабирование — это по сути «купить машину побольше/посильнее» — (виртуальная) машина с большим числом ядер, лучшей вычислительной мощностью и большей памятью. В случае с рапределёнными системами, вертикальное масштабирование обычно менее популярно, поскольку оно может быть более дорогостоящим, чем масштабирование горизонтальное. Однако, некоторые известные большие сайты, вроде Stack Overflow, успешно масштабировались вертикально для соответствия нагрузке.
@python_job_interview
Ответ
В больших системах, которые обрабатывают миллионы событий в день, некоторые вещи просто по определению обязаны пойти не по плану. Вот почему прежде, чем погружаться в планирование системы, нужно сделать самый важный шаг — принять решение о том, что для нас означает «здоровая» система. Степень «здоровья» должна быть чем-то таким, что на самом деле можно измерить. Общепринятым способом измерения «здоровья» системы являются SLA (service level agreements). Вот некоторые из самых распространённых видов SLA:
Доступность (Availability): процент времени, который сервис является работоспособным. Пусть существует искушение достичь 100% доступности, достижение этого результата может оказаться по-настоящему сложным занятием, да ещё вдобавок и весьма дорогостоящим. Даже крупные и критичные системы вроде сети карт VISA, Gmail или интернет-провайдеров не имеют 100% доступности — за годы они накопят секунды, минуты или часы, проведённые в даунтайме. Для многих систем, доступность в четыре девятки (99.99%, или примерно 50 минут даунтайма в год) считается высокой доступностью. Для того, чтобы добраться до этого уровня, придётся изрядно попотеть.
Точность (Accuracy): является ли допустимой потеря данных или их неточность? Если да, то какой процент является приемлимым? Для системы платежей, над которой я работал, этот показатель должен был составлять 100%, поскольку данные терять было нельзя.
Пропускная способность/мощность (Capacity): какую нагрузку должна выдерживать система? Этот показатель обычно выражается в запросах в секунду.
Задержка (Latency): за какое время система должна отвечать? За какое время должны быть обслужены 95% и 99% запросов? В подобных системах обычно многие из запросов являются «шумом», поэтому задержки p95 и p99 находят более практическое применение в реальном мире.
Горизонтальное и вертикальное масштабирование
По мере роста бизнеса, который использует нашу свежесозданную систему, нагрузка на неё будет лишь увеличиваться. В определенный момент, существующая установка будет неспособна выдержать дальнейшее увеличение нагрузки, и нам потребуется увеличить допустимую нагрузку. Две общепринятые стратегии масштабирования — это вертикальное или горизонтальное масштабирование.
Горизонтальное масштабирование заключается в добавлении большего количества машин (или узлов) в систему для увеличения пропускной способности (capacity). Горизонтальное масштабирование — это самый популярный способ масштабирования распределённых систем.
Вертикальное масштабирование — это по сути «купить машину побольше/посильнее» — (виртуальная) машина с большим числом ядер, лучшей вычислительной мощностью и большей памятью. В случае с рапределёнными системами, вертикальное масштабирование обычно менее популярно, поскольку оно может быть более дорогостоящим, чем масштабирование горизонтальное. Однако, некоторые известные большие сайты, вроде Stack Overflow, успешно масштабировались вертикально для соответствия нагрузке.
@python_job_interview
Задача. Есть три функции, в которых выполняются базовые операции (сортировка, фильтрация, возведение массива в квадрат). Нужно упорядочить эти три функции в порядке возрастания времени, идущего на их выполнение.
То есть на входе все функции имеют одинаковые данные, на выходе выдают одинаковый результат. Но из-за того, что внутри операции выполняются в разном порядке, время выполнения будет отличаться. Здесь нужно ориентироваться в алгоритмах и понимать, что происходит с твоими данными в процессе. Эту задачу может решить Junior, а может не решить и Middle. Казалось бы, такая мелочь, но когда мы работаем с большим количеством данных, важно, чтобы код был оптимизирован и программа выполнялась максимально быстро.
@python_job_interview
def f1(lIn):
l1 = sorted(lIn)
l2 = [i for i in l1 if i<0.5]
return [i*i for i in l2]
def f2(lIn):
l1 = [i for i in lIn if i<0.5]
l2 = sorted(l1)
return [i*i for i in l2]
def f3(lIn):
l1 = [i*i for i in lIn]
l2 = sorted(l1)
return [i for i in l1 if i<(0.5*0.5)]
То есть на входе все функции имеют одинаковые данные, на выходе выдают одинаковый результат. Но из-за того, что внутри операции выполняются в разном порядке, время выполнения будет отличаться. Здесь нужно ориентироваться в алгоритмах и понимать, что происходит с твоими данными в процессе. Эту задачу может решить Junior, а может не решить и Middle. Казалось бы, такая мелочь, но когда мы работаем с большим количеством данных, важно, чтобы код был оптимизирован и программа выполнялась максимально быстро.
@python_job_interview
#Вопросы_с_собеседования
❓Напишите программу, которая возвращает количество гласных букв в строке
Наша программа при помощи регулярного выражения, вычисляет количество гласных (A, E, I, O, U, Y) в строке.
@python_job_interview
❓Напишите программу, которая возвращает количество гласных букв в строке
Наша программа при помощи регулярного выражения, вычисляет количество гласных (A, E, I, O, U, Y) в строке.
@python_job_interview
English for Developers - канал для тех, кто хочет учить технический английский. От создатателей популярного ит-канала Книги программиста.
1. техническая лексика
2. опросы на английском
3. шутки на английском
Подписывайтесь, проходите опросы, читайте полезные прогерские фразы на английском: english_forprogrammers.
1 канал вместо тысячи учебников и курсов
1. техническая лексика
2. опросы на английском
3. шутки на английском
Подписывайтесь, проходите опросы, читайте полезные прогерские фразы на английском: english_forprogrammers.
1 канал вместо тысячи учебников и курсов
Как выполняется интерполяция строк?
Без импорта класса Template есть три способа интерполяции строк:
@python_job_interview
Без импорта класса Template есть три способа интерполяции строк:
name = 'Chris'
# 1. f strings
print(f'Hello {name}')
# 2. % operator
print('Hey %s %s' % (name, name))
# 3. format
print(
"My name is {}".format((name))
)
@python_job_interview
Опишите сложость исполнения основных операций над словарями
Ответ
В таблице ниже приводится усреднённая сложность. Амортизированный худший случай обычно описывается O(n). Для усреднённой сложности предполагается, что хеш-функция для словарей в состоянии сделать конфликты редкими. Также предполагается, что ключи, используемые в параметрах, выбираются равномерно из множества всех существующих ключей.
Указанная ниже сложность справледлива и для defaultdict (вместе с доступными операциями они наследуют от словарей и их сложности). Предполагается, что конструирование нового defaultdict имеет сложность O(1) (что справледливо для часто используемых int(), list(), set()).
Для словарей, где ключи являются строками, используется быстрый путь. Это не оказывает влияния на алгоритмическую сложность, однако сильно влияет на постоянные факторы — то, на сколько быстро исполяется типовое приложение.
@python_job_interview
Ответ
В таблице ниже приводится усреднённая сложность. Амортизированный худший случай обычно описывается O(n). Для усреднённой сложности предполагается, что хеш-функция для словарей в состоянии сделать конфликты редкими. Также предполагается, что ключи, используемые в параметрах, выбираются равномерно из множества всех существующих ключей.
Указанная ниже сложность справледлива и для defaultdict (вместе с доступными операциями они наследуют от словарей и их сложности). Предполагается, что конструирование нового defaultdict имеет сложность O(1) (что справледливо для часто используемых int(), list(), set()).
Для словарей, где ключи являются строками, используется быстрый путь. Это не оказывает влияния на алгоритмическую сложность, однако сильно влияет на постоянные факторы — то, на сколько быстро исполяется типовое приложение.
@python_job_interview
Какая Встроенная база данных поддерживается в Python? Расскажите о работе с ней.
Ответ
«Встроенность» предполагает, что вам не нужно запускать pip install для получения библиотеки. Просто импортируйте ее с помощью:
Создание соединения с БД
Не беспокойтесь о драйверах, строках подключения и т.д. Вы можете создать базу данных SQLite и задать такой простой объект подключения, как:
После запуска этой строки кода происходит создание с БД и активируется подключение к ней. Дело в том, что базы данных, к которой мы просим подключиться Python, не существует, поэтому он автоматически создает пустую. Также мы можем ввести точно такой же код для подключения к уже существующей базе данных.
Создание таблицы
Теперь создадим таблицу:
Мы добавили три столбца в таблицу USER. Как видите, SQLite действительно легка и при этом поддерживает все основные функции обычной реляционной СУБД, такие как тип данных, обнуляемый тип, первичный ключ и автоинкремент.
После запуска этого кода создается таблица, но она ничего не выводит.
Включение записей
Вставим несколько записей в только что созданную таблицу USER, чтобы доказать, что она действительно создана.
Предположим, мы хотим вставить сразу несколько записей. Выполним:
После запуска кода не появилось никаких предупреждений, значит все прошло успешно.
Запрос к таблице
Пришло время удостовериться, что все сделано правильно. Выполним запрос к таблице на возврат образцов строк.
➡️ Читать дальше
@python_job_interview
Ответ
«Встроенность» предполагает, что вам не нужно запускать pip install для получения библиотеки. Просто импортируйте ее с помощью:
import sqlite3 as sl
Создание соединения с БД
Не беспокойтесь о драйверах, строках подключения и т.д. Вы можете создать базу данных SQLite и задать такой простой объект подключения, как:
con = sl.connect('my-test.db')
После запуска этой строки кода происходит создание с БД и активируется подключение к ней. Дело в том, что базы данных, к которой мы просим подключиться Python, не существует, поэтому он автоматически создает пустую. Также мы можем ввести точно такой же код для подключения к уже существующей базе данных.
Создание таблицы
Теперь создадим таблицу:
with con:
con.execute("""
CREATE TABLE USER (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name TEXT,
age INTEGER
);
""")
Мы добавили три столбца в таблицу USER. Как видите, SQLite действительно легка и при этом поддерживает все основные функции обычной реляционной СУБД, такие как тип данных, обнуляемый тип, первичный ключ и автоинкремент.
После запуска этого кода создается таблица, но она ничего не выводит.
Включение записей
Вставим несколько записей в только что созданную таблицу USER, чтобы доказать, что она действительно создана.
Предположим, мы хотим вставить сразу несколько записей. Выполним:
sql = 'INSERT INTO USER (id, name, age) values(?, ?, ?)'
data = [
(1, 'Alice', 21),
(2, 'Bob', 22),
(3, 'Chris', 23)
]
Определяем оператор SQL с вопросительными знаками ? в качестве заполнителя. Теперь создадим образцы данных для вставки, а затем вставим их с помощью объекта подключения:with con:
con.executemany(sql, data)
После запуска кода не появилось никаких предупреждений, значит все прошло успешно.
Запрос к таблице
Пришло время удостовериться, что все сделано правильно. Выполним запрос к таблице на возврат образцов строк.
with con:
data = con.execute("SELECT * FROM USER WHERE age <= 22")
for row in data:
print(row)
➡️ Читать дальше
@python_job_interview
❓ Задача с собеседования | Уровень: #Medium
Условие:
Ваша задача — написать функцию, которая принимает неограниченное количество списков и возвращает только те элементы, что есть в каждом списке.
Пример:
➡️Делитесь своим решением в комментариях👇
#задача_с_собеседования
@python_job_interview
Условие:
Ваша задача — написать функцию, которая принимает неограниченное количество списков и возвращает только те элементы, что есть в каждом списке.
Пример:
find_values([11, 10, 3], [10, 3, 5, 11], [11, 10]) -> [11, 10]
find_values([8, 4, 7, "hi"], [8, "hi"], [4, "hi"]) -> ['hi']
find_values([1, 4, 3], [6, 2, 8], ["4", "hi"]) -> []
➡️Делитесь своим решением в комментариях👇
#задача_с_собеседования
@python_job_interview
Что такое «монкей патчинг» и когда он уместен?
«Монкей патчинг» меняет поведение объекта или функции после того, как он/она будет определён/а.
Чаще всего это – довольно плохая идея, предпочтительно такие вещи определять явным способом. Одна из причин применения «монкей патчинга» - тестирование. Пакет mock очень полезен с для этих целей.
Почему это важно?
Это показывает, собеседуемый знаком методологией модульного тестирования. Упоминание о «моней патчинге» покажет, что программист за поддерживаемый программный код (те кто против – менее эффективны). Помните принцип KISS? И это показывает, что вы знакомы, как работает Python на более низком уровне, как функции хранятся, вызываются и прочее.
PS: стоит немного почитать о mock если вы ещё не сделали этого. Это довольно полезно.
@python_job_interview
«Монкей патчинг» меняет поведение объекта или функции после того, как он/она будет определён/а.
import datetime
datetime.datetime.now = lambda: datetime.datetime(2022, 09, 09
)Чаще всего это – довольно плохая идея, предпочтительно такие вещи определять явным способом. Одна из причин применения «монкей патчинга» - тестирование. Пакет mock очень полезен с для этих целей.
Почему это важно?
Это показывает, собеседуемый знаком методологией модульного тестирования. Упоминание о «моней патчинге» покажет, что программист за поддерживаемый программный код (те кто против – менее эффективны). Помните принцип KISS? И это показывает, что вы знакомы, как работает Python на более низком уровне, как функции хранятся, вызываются и прочее.
PS: стоит немного почитать о mock если вы ещё не сделали этого. Это довольно полезно.
@python_job_interview
Что распечатает код:
Ответ
Почему?
Первый вызов функции волне очевиден, цикл добавляет 0, а затем 1 в пустой список. l – имя переменной которая указывает на список, хранящийся в памяти. Второй вызов начинается с создания нового списка, хранящегося в новом блоке памяти. l ссылается на новый список. Затем добавляются 0, 1 и 4 к новому списку. В третьем вызове функции происходит что-то странное. Она использует исходный список, хранящийся в исходной области памяти. Именно поэтому он начинается с 0 и 1.
Протестируйте следующий код, для понимания:
@python_job_interview
def f(x,l=[]):
for i in range(x):
l.append(i*i)
print(l)
f(2)
f(3,[3,2,1])
f(3)
Ответ
[0, 1]
[3, 2, 1, 0, 1, 4]
[0, 1, 0, 1, 4]
Почему?
Первый вызов функции волне очевиден, цикл добавляет 0, а затем 1 в пустой список. l – имя переменной которая указывает на список, хранящийся в памяти. Второй вызов начинается с создания нового списка, хранящегося в новом блоке памяти. l ссылается на новый список. Затем добавляются 0, 1 и 4 к новому списку. В третьем вызове функции происходит что-то странное. Она использует исходный список, хранящийся в исходной области памяти. Именно поэтому он начинается с 0 и 1.
Протестируйте следующий код, для понимания:
l_mem = []
l = l_mem # первый вызов
for i in range(2):
l.append(i*i)
print(l) # [0, 1]
l = [3,2,1] # второй вызов
for i in range(3):
l.append(i*i)
print(l) # [3, 2, 1, 0, 1, 4]
l = l_mem # третий вызов
for i in range(3):
l.append(i*i)
print(l) # [0, 1, 0, 1, 4]
@python_job_interview
Расскажите о сборщике мусора в Python
Как правило, вам не нужно беспокоиться о сборщике мусора и работе с памятью когда вы пишете код на Python. Как только объекты больше не нужны, Python автоматически освобождает память из под них. Несмотря на это, понимание как работает GC поможет писать более качественный код.
Менеджер памяти
В отличие от других популярных языков, Python не освобождает всю память обратно операционной системе как только он удаляет какой либо объект. Вместо этого, он использует дополнительный менеджер памяти, предназначенный для маленьких объектов (размер которых меньше чем 512 байт). Для работы с такими объектами он выделяет большие блоки памяти, в которых в дальнейшем будет хранится множество маленьких объектов.
Как только один из маленьких объект удаляется — память из под него не переходит операционной системе, Python оставляет её для новых объектов с таким же размером. Если в одном из выделенных блоков памяти не осталось объектов, то Python может высвободить его операционной системе. Как правило, высвобождение блоков случается когда скрипт создает множество временных объектов.
Таким образом, если долгоживущий Python процесс с течением времени начинает потреблять больше памяти, то это совсем не означает, что в вашем коде есть проблема с утечкой памяти. Если вы хотите узнать больше о менеджере памяти в Python, вы можете прочитать об этом в другой моей статье (англ.).
Алгоритмы сборки мусора
Стандартный интерпретатор питона (CPython) использует сразу два алгоритма, подсчет ссылок и generational garbage collector (далее GC), более известный как стандартный модуль gc из Python.
Алгоритм подсчета ссылок очень простой и эффективный, но у него есть один большой недостаток. Он не умеет определять циклические ссылки. Именно из-за этого, в питоне существует дополнительный сборщик, именуемый поколенческий GC, который следит за объектами с потенциальными циклическими ссылками.
В Python, алгоритм подсчета ссылок является фундаментальным и не может отключен, тогда как GC опционален и может быть отключен.
Алгоритм подсчета ссылок
Алгоритм подсчета ссылок это одна из самых простых техник для сборки мусора. Объекты удаляются как только на них больше нет ссылок.
В Python, переменные не хранят значения, а выступают в роли ссылок на объекты. То есть когда вы присваивайте значение новой переменной, то сначала создается объект с этим значением, а уже потом переменная начинает ссылаться на него. На один объект может ссылаться множество переменных.
Каждый объект в Python содержит дополнительное поле (счетчик ссылок), в котором хранится количество ссылок на него. Как только кто-то ссылается на объект, это поле увеличивается на единицу. Если по какой-то причине ссылка пропадает, то это поле уменьшается на один.
Примеры, когда количество ссылок увеличивается:
- оператор присваивания
- передача аргументов
- вставка нового объекта в лист (увеличивается количество ссылок для объекта)
конструция вида foo = bar (foo начинается ссылаться на тот же объект, что и bar)
Как только счетчик ссылок для определенного объекта достигает нуля интерпретатор запускает процесс уничтожения объекта. Если удаленный объект содержал ссылки на другие объекты, то эти ссылки также удаляются. Таким образом, удаление одного объекта может повлечь за собой удаление других.
Например, если удаляется список, то счетчик ссылок во всех его элементах уменьшается на один. Если все объекты внутри списка больше нигде не используются, то они также будут удалены.
Переменные, которые объявлены вне функций, классов и блоков называются глобальными. Как правило, жизненный цикл таких переменных равен жизни Python процесса. Таким образом, количество ссылок на объекты на которые ссылаются глобальные переменные никогда не падает до нуля.
Переменные, которые объявлены внутри блока имеют локальную видимость (они видны только внутри блока). Как только интерпретатор питона выходит из блока он уничтожает все ссылки созданные локальными переменными внутри него.
Вы всегда можете проверить количество ссылок используя функцию sys.getrefcount.
@python_job_interview
Как правило, вам не нужно беспокоиться о сборщике мусора и работе с памятью когда вы пишете код на Python. Как только объекты больше не нужны, Python автоматически освобождает память из под них. Несмотря на это, понимание как работает GC поможет писать более качественный код.
Менеджер памяти
В отличие от других популярных языков, Python не освобождает всю память обратно операционной системе как только он удаляет какой либо объект. Вместо этого, он использует дополнительный менеджер памяти, предназначенный для маленьких объектов (размер которых меньше чем 512 байт). Для работы с такими объектами он выделяет большие блоки памяти, в которых в дальнейшем будет хранится множество маленьких объектов.
Как только один из маленьких объект удаляется — память из под него не переходит операционной системе, Python оставляет её для новых объектов с таким же размером. Если в одном из выделенных блоков памяти не осталось объектов, то Python может высвободить его операционной системе. Как правило, высвобождение блоков случается когда скрипт создает множество временных объектов.
Таким образом, если долгоживущий Python процесс с течением времени начинает потреблять больше памяти, то это совсем не означает, что в вашем коде есть проблема с утечкой памяти. Если вы хотите узнать больше о менеджере памяти в Python, вы можете прочитать об этом в другой моей статье (англ.).
Алгоритмы сборки мусора
Стандартный интерпретатор питона (CPython) использует сразу два алгоритма, подсчет ссылок и generational garbage collector (далее GC), более известный как стандартный модуль gc из Python.
Алгоритм подсчета ссылок очень простой и эффективный, но у него есть один большой недостаток. Он не умеет определять циклические ссылки. Именно из-за этого, в питоне существует дополнительный сборщик, именуемый поколенческий GC, который следит за объектами с потенциальными циклическими ссылками.
В Python, алгоритм подсчета ссылок является фундаментальным и не может отключен, тогда как GC опционален и может быть отключен.
Алгоритм подсчета ссылок
Алгоритм подсчета ссылок это одна из самых простых техник для сборки мусора. Объекты удаляются как только на них больше нет ссылок.
В Python, переменные не хранят значения, а выступают в роли ссылок на объекты. То есть когда вы присваивайте значение новой переменной, то сначала создается объект с этим значением, а уже потом переменная начинает ссылаться на него. На один объект может ссылаться множество переменных.
Каждый объект в Python содержит дополнительное поле (счетчик ссылок), в котором хранится количество ссылок на него. Как только кто-то ссылается на объект, это поле увеличивается на единицу. Если по какой-то причине ссылка пропадает, то это поле уменьшается на один.
Примеры, когда количество ссылок увеличивается:
- оператор присваивания
- передача аргументов
- вставка нового объекта в лист (увеличивается количество ссылок для объекта)
конструция вида foo = bar (foo начинается ссылаться на тот же объект, что и bar)
Как только счетчик ссылок для определенного объекта достигает нуля интерпретатор запускает процесс уничтожения объекта. Если удаленный объект содержал ссылки на другие объекты, то эти ссылки также удаляются. Таким образом, удаление одного объекта может повлечь за собой удаление других.
Например, если удаляется список, то счетчик ссылок во всех его элементах уменьшается на один. Если все объекты внутри списка больше нигде не используются, то они также будут удалены.
Переменные, которые объявлены вне функций, классов и блоков называются глобальными. Как правило, жизненный цикл таких переменных равен жизни Python процесса. Таким образом, количество ссылок на объекты на которые ссылаются глобальные переменные никогда не падает до нуля.
Переменные, которые объявлены внутри блока имеют локальную видимость (они видны только внутри блока). Как только интерпретатор питона выходит из блока он уничтожает все ссылки созданные локальными переменными внутри него.
Вы всегда можете проверить количество ссылок используя функцию sys.getrefcount.
@python_job_interview
Чувствителен ли Python к регистру?
Ответ
Язык программирования считается чувствительным к регистру, если он различает такие идентификаторы, как «myname» и «Myname». Проще говоря, он заботится, являются ли символы строчными или прописными.
Давайте посмотрим на пример:
Возникновение ошибки NameError означает, что Python чувствителен к регистру.
@python_job_interview
Ответ
Язык программирования считается чувствительным к регистру, если он различает такие идентификаторы, как «myname» и «Myname». Проще говоря, он заботится, являются ли символы строчными или прописными.
Давайте посмотрим на пример:
>>> myname="John"
>>> Myname
Traceback (most recent call last):
File "", line 1, in
Myname
NameError: name 'Myname' is not defined
Возникновение ошибки NameError означает, что Python чувствителен к регистру.
@python_job_interview
Какие библиотеки установлены в питоне по-умолчанию?
Встроенные модули
Список встроенных модлей из стандартной библиотеки Питона смотрите в докментации: The Python Standard Library.
Из перечисленных встроенными являются collections, datetime, gc, json. Остальные необходимо устанавливать отдельно, например, через пакетный менеджер Питона pip.
Порядок импортов
Помимо этого, в соответствии с официальными рекомендациями PEP, порядок подключения библиотек следует использовать такой:
Стандартные библиотеки.
Используемые сторонние модули.
Локальные модули вашего приложения/библиотеки.
В некоторых источниках также советуют отделять несколько импортов из одного модуля, а импорты с общей приоритетностью сортировать в алфавитном порядке.
Например, вот так:
Виртуальное окружение с зависимостями
Если в проекте много кода с разными зависимостями, то для выявления используемых библиотек следует использовать виртуальное окружение, например, модуль virtualenv. Виртуальное окружение позволяет инкапсулироваться от модулей, установленных в Питоне глобально, устанавливая библиотеки с нужными версиями в рамках конкретного проекта. По этой теме много статей как на английском, так и на русском. При запуске проекта в виртуальном окружении Вы увидите ошибки о недостающих библиотеках, которые нужно установить в локальном окружении проекта.
Однако виртуальные окружения существуют для использования модулей на месте, они не сохраняются в системах контроля версий. Для этого используется файл requirements.txt, в котором описываются нужные библиотеки и опционально их версии. Для быстрого создания этого файла можно заморозить текущие библиотеки из локального pip'a, а при создании нового окружения можно будет их легко установить из этого файла. Подробнее читайте в документации: PIP > User Guide > Requirements Files.
@python_job_interview
Встроенные модули
Список встроенных модлей из стандартной библиотеки Питона смотрите в докментации: The Python Standard Library.
Из перечисленных встроенными являются collections, datetime, gc, json. Остальные необходимо устанавливать отдельно, например, через пакетный менеджер Питона pip.
Порядок импортов
Помимо этого, в соответствии с официальными рекомендациями PEP, порядок подключения библиотек следует использовать такой:
Стандартные библиотеки.
Используемые сторонние модули.
Локальные модули вашего приложения/библиотеки.
В некоторых источниках также советуют отделять несколько импортов из одного модуля, а импорты с общей приоритетностью сортировать в алфавитном порядке.
Например, вот так:
# Стандартные модули
from collections import defaultdict
import datetime
import gc
import json
# Сторонние модули
from clickhouse_driver import Client
import psycopg2
import tqdm
# Отдельно несколько строк с Торнадо
from tornado.web import Application, RequestHandler
from tornado.ioloop import IOLoop
Виртуальное окружение с зависимостями
Если в проекте много кода с разными зависимостями, то для выявления используемых библиотек следует использовать виртуальное окружение, например, модуль virtualenv. Виртуальное окружение позволяет инкапсулироваться от модулей, установленных в Питоне глобально, устанавливая библиотеки с нужными версиями в рамках конкретного проекта. По этой теме много статей как на английском, так и на русском. При запуске проекта в виртуальном окружении Вы увидите ошибки о недостающих библиотеках, которые нужно установить в локальном окружении проекта.
Однако виртуальные окружения существуют для использования модулей на месте, они не сохраняются в системах контроля версий. Для этого используется файл requirements.txt, в котором описываются нужные библиотеки и опционально их версии. Для быстрого создания этого файла можно заморозить текущие библиотеки из локального pip'a, а при создании нового окружения можно будет их легко установить из этого файла. Подробнее читайте в документации: PIP > User Guide > Requirements Files.
@python_job_interview
Что такое GIL?
GIL или Global Interpreter Lock — это мьютекс, используемый для ограничения доступа к объектам Python. Он синхронизирует потоки и предотвращает их одновременное выполнение.
↪️ Подробно про GIL
@python_job_interview
GIL или Global Interpreter Lock — это мьютекс, используемый для ограничения доступа к объектам Python. Он синхронизирует потоки и предотвращает их одновременное выполнение.
@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Ответ
Пространство имен представляет собой систему имен, которая используется для обеспечения уникальности наименования всех объектов в программе, чтобы избежать возможных конфликтов. В Python эти пространства имен реализованы как словари с именем в качестве ключа и объектом в качестве значения. В результате разные пространства могут давать своим объектам одинаковые имена.
Ниже приведены три типа пространств имен в Python:
- Локальное пространство имен — включает локальные имена внутри функции. Локальное пространство имен временно создается во время вызова функции и очищается при возврате из нее.
- Глобальное пространство имен — состоит из имен различных импортированных пакетов/модулей, которые в настоящее время используются в проекте. Глобальное пространство имен создается при импорте пакета в скрипт, и оно доступно до тех пор, пока скрипт не закончит выполнение.
- Встроенное пространство имен — оно включает встроенные функции Python и встроенные имена для различных типов исключений.
@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥 Полезнейшая Подборка каналов
🖥 Python
@pythonl
@pro_python_code – погружение в python
@python_job_interview – подготовка к Python собеседованию
@python_testit тесты на python
@pythonlbooks - книги Python
@Django_pythonl django
@python_djangojobs - работа Python
@python_django_work
🖥 Machine learning
@ai_machinelearning_big_data – все о машинном обучении
@data_analysis_ml – все о анализе данных.
@machinelearning_ru – машинное обучении на русском от новичка до профессионала.
@machinelearning_interview – подготовка к собеседования Data Science
@datascienceiot – бесплатные книги Machine learning
@ArtificialIntelligencedl – канал о искусственном интеллекте
@neural – все о нейронных сетях
@machinee_learning – чат о машинном обучении
@datascienceml_jobs - работа ds, ml
@Machinelearning_Jobs
🖥 Java
@javatg - Java для програмистов
@javachats Java чат
@java_library - книги Java
@android_its Android разработка
@java_quizes - тесты Java
@Java_workit - работа Java
@progersit - шпаргалки ит
🖥 Javascript / front
@javascriptv - javascript изучение
@about_javascript - javascript продвинутый
@JavaScript_testit -тесты JS
@htmlcssjavas - web
@hashdev - web разработка
👣 Golang
@golang_interview - вопросы и ответы с собеседований по Go. Для всех уровней разработчиков.
@Golang_google - go для разработчиков
@golangtests - тесты и задачи GO
@golangl - чат Golang
@GolangJobsit - вакансии и работа GO
@golang_jobsgo - чат вакансий
@golang_books - книги Golang
@golang_speak - обсуждение задач Go
🖥 Linux
@linux_kal - чат kali linux
@linuxkalii - linux kali
@linux_read - книги linux
👷♂️ IT работа
@hr_itwork - ит-ваканнсии
🖥 SQL
@sqlhub - базы данных
@chat_sql - базы данных чат
🤡It memes
@memes_prog - ит-мемы
⚙️ Rust
@rust_code - язык программирования rust
@rust_chats - чат rust
#️⃣ c# c++
@csharp_ci - c# c++кодинг
@csharp_cplus чат
📓 Книги
@programming_books_it
@datascienceiot
@pythonlbooks
@golang_books
@frontendbooksit
@progersit
@linux_read
@java_library
@frontendbooksit
📢 English for coders
@english_forprogrammers - Английский для программистов
🖥 Github
@github_code
@pythonl
@pro_python_code – погружение в python
@python_job_interview – подготовка к Python собеседованию
@python_testit тесты на python
@pythonlbooks - книги Python
@Django_pythonl django
@python_djangojobs - работа Python
@python_django_work
@ai_machinelearning_big_data – все о машинном обучении
@data_analysis_ml – все о анализе данных.
@machinelearning_ru – машинное обучении на русском от новичка до профессионала.
@machinelearning_interview – подготовка к собеседования Data Science
@datascienceiot – бесплатные книги Machine learning
@ArtificialIntelligencedl – канал о искусственном интеллекте
@neural – все о нейронных сетях
@machinee_learning – чат о машинном обучении
@datascienceml_jobs - работа ds, ml
@Machinelearning_Jobs
@javatg - Java для програмистов
@javachats Java чат
@java_library - книги Java
@android_its Android разработка
@java_quizes - тесты Java
@Java_workit - работа Java
@progersit - шпаргалки ит
@javascriptv - javascript изучение
@about_javascript - javascript продвинутый
@JavaScript_testit -тесты JS
@htmlcssjavas - web
@hashdev - web разработка
@golang_interview - вопросы и ответы с собеседований по Go. Для всех уровней разработчиков.
@Golang_google - go для разработчиков
@golangtests - тесты и задачи GO
@golangl - чат Golang
@GolangJobsit - вакансии и работа GO
@golang_jobsgo - чат вакансий
@golang_books - книги Golang
@golang_speak - обсуждение задач Go
@linux_kal - чат kali linux
@linuxkalii - linux kali
@linux_read - книги linux
👷♂️ IT работа
@hr_itwork - ит-ваканнсии
@sqlhub - базы данных
@chat_sql - базы данных чат
🤡It memes
@memes_prog - ит-мемы
⚙️ Rust
@rust_code - язык программирования rust
@rust_chats - чат rust
#️⃣ c# c++
@csharp_ci - c# c++кодинг
@csharp_cplus чат
📓 Книги
@programming_books_it
@datascienceiot
@pythonlbooks
@golang_books
@frontendbooksit
@progersit
@linux_read
@java_library
@frontendbooksit
@english_forprogrammers - Английский для программистов
@github_code
Please open Telegram to view this post
VIEW IN TELEGRAM