Магические квадраты издавна интриговали воображение людей: дата изготовления древнейшей сохранившейся таблицы относится к 2200 г. до н.э. Магический квадрат – это квадратная таблица размера n х n, составленная из всех чисел 1, 2, 3 … n2 таким образом, что суммы по каждому столбцу, каждой строке и каждой диагонали равны между собой. Напишем программу, которая определяет, можно ли считать матрицу магическим квадратом.
Входные данные:
Число n, затем n строк с n цифр в каждой.
#Пример ввода
3
8 1 6
3 5 7
4 9 2
Выходные данные:
YES, если введенная матрица является магическим квадратом, и NO в обратном случае.
#Пример вывода
YES
Решение
Способ 1:
n = int(input())
matrix = [list(map(int, input().split())) for _ in range(n)]
if all(i in sum(matrix,[]) for i in range(1, n**2 + 1)):
print('YES' if all(sum(i) == sum(j) == sum([matrix[i][i] for i in range(n)]) == sum([matrix[n-i-1][i] for i in range(n)]) for i in matrix for j in list(map(list, zip(*matrix)))) else 'NO')
else:
print('NO')
Способ 2 – с магической константой и множествами:
n = int(input())
square = [[*map(int, input().split())] for _ in range(n)]
m_const = n * (1 + n ** 2) // 2
print(('NO', 'YES')[all(sum(el) == m_const for x in (((square[i][i] for i in range(n)),(square[i][~i] for i in range(n))), square, zip(*square)) for el in x) and set(sum(square, [])) == set(range(1, n ** 2 + 1))])
@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥3❤1👎1
🌀 Заполнение матрицы по спирали
Эта классическая задача часто встречается на собеседованиях и олимпиадах. Рассмотрим несколько способов решения на Python.
На вход программе подаются два натуральных числа n и m. Напишите программу, которая создает матрицу размером n х m, заполнив ее по спирали числами от 1 до n x m. Спираль начинается в левом верхнем углу и закручивается по часовой стрелке.
Пример ввода:
Пример вывода:
Решение
Способ 1:
Способ 2:
Способ 3:
@python_job_interview
Эта классическая задача часто встречается на собеседованиях и олимпиадах. Рассмотрим несколько способов решения на Python.
На вход программе подаются два натуральных числа n и m. Напишите программу, которая создает матрицу размером n х m, заполнив ее по спирали числами от 1 до n x m. Спираль начинается в левом верхнем углу и закручивается по часовой стрелке.
Пример ввода:
7 6
Пример вывода:
1 2 3 4 5 6
22 23 24 25 26 7
21 36 37 38 27 8
20 35 42 39 28 9
19 34 41 40 29 10
18 33 32 31 30 11
17 16 15 14 13 12
Решение
Способ 1:
n, m = map(int, input().split())
matrix = [[0] * m for _ in range(n)]
dx, dy, x, y = 0, 1, 0, 0
for i in range(1, n * m + 1):
matrix[x][y] = i
if matrix[(x + dx) % n][(y + dy) % m]:
dx, dy = dy, -dx
x += dx
y += dy
for line in matrix:
print(*(f'{i:<3}' for i in line), sep='')
Способ 2:
n, m = (int(i) for i in input().split())
spiral = []
x, y, dx, dy, k = 0, 0, 1, 0, 1
spiral = [[0]* n for _ in range(m)]
for i in range(1, n * m + 1):
spiral[x][y] = i
nx, ny = x + dx, y + dy
if 0 <= nx < m and 0 <= ny < n and spiral[nx][ny] == 0:
x, y = nx, ny
else:
dx, dy = -dy, dx
x, y = x + dx, y + dy
for i in range(n):
for j in range(m):
print(str(spiral[j][i]).ljust(3), end=' ')
print()
Способ 3:
n, m = [int(i) for i in input().split()]
spiral = [[0] * m for _ in range(n)]
c = 1
for k in range(min(n // 2 + 1, m //2 + 1)):
for j in range(k, m - k):
if spiral[k][j] == 0:
spiral[k][j] = c
c += 1
for i in range(1 + k, n - k):
if spiral[i][m - k - 1] == 0:
spiral[i][m - k - 1] = c
c += 1
for j in range(m - k - 2, k - 1, -1):
if spiral[n - k - 1][j] == 0:
spiral[n - k - 1][j] = c
@python_job_interview
👍15🔥3❤1
📚 20 лучших бесплатных книг по Python для начинающих и продвинутых программистов
Настоящий новогодний подарок всем Python разработчикам.
✔️ Смотреть список
@python_job_interview
Настоящий новогодний подарок всем Python разработчикам.
✔️ Смотреть список
@python_job_interview
👍6🔥3❤2
Латинский квадрат – это квадратная матрица размером n x n, каждая строка и каждый столбец которой содержат все числа от 1 до n. В Средние века латинским квадратам приписывались магические свойства: такие таблицы использовались во время проведения оккультных ритуалов. Напишите программу для определения латинского квадрата.
Входные данные:
число n – количество строк и столбцов в матрице;
n строк, c n чисел в каждой.
Выходные данные:
Программа должна вывести YES, если введенная матрица является латинским квадратом, и NO в обратном случае.
# Пример ввода:
4
2 3 4 1
3 4 1 2
4 1 2 3
1 2 3 4
Пример вывода:
#YES
Решение
Первый способ– с использованием функции sorted():
n = int(input())
matrix = [[int(i) for i in input().split()] for _ in range(n)]
for i in range(n):
if sorted(matrix[i]) != list(range(1, n + 1)) or sorted([matrix[j][i] for j in range(n)]) != list(range(1, n + 1)):
print('NO')
break
else:
print('YES')
Второй способ – с использованием функции all():
n = int(input())
square = [[*map(int,input().split()) ] for i in range(n)]
a = all([all([c in row for c in range(1,n + 1)]) for row in square])
b = all([all([c in row1 for c in range(1, n + 1)]) for row1 in zip(*square)])
print(('NO','YES')[a and b])
Третий способ – с использованием транспонирования и множеств:
n = int(input())
sq_set = set(range(1, n + 1))
square = []
for i in range(n):
square.append(list(map(int, input().split())))
tr_square = list(map(list, zip(*square)))
vector_1 = [set(row) == sq_set for row in square]
vector_2 = [set(row) == sq_set for row in tr_square]
vector = vector_1 + vector_2
if all(vector):
print('YES')
else:
print('NO')
@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18😱4❤1🔥1
Нужно реализовать HTTP сервис для голосования. Например, для выбора самого популярного покемона. UI не нужен, достаточно сделать JSON API сервис. Должна быть возможность:
Задача
Нужно реализовать HTTP сервис для голосования. Например, для выбора самого популярного покемона. UI не нужен, достаточно сделать JSON API сервис. Должна быть возможность:
▪ Создать новое голосование с разными вариантами ответов
▪ Отдать свой голос за какой-либо вариант
▪ Получить текущий результат голосования
Реализовать методы:
- POST /api/createPoll/ создать голосование c вариантами ответов
- POST /api/poll/ проголосовать за конкретный вариант: <poll_id, choice_id>
- POST /api/getResult/ получить результат по конкретному голосованию: <poll_id>
Структура и формат входных и выходных данных на ваше усмотрение.
Описание идеального решения
▪ Задание декомпозировано, составлен иерархический список работ. Каждый пункт из этого списка может быть реализован за небольшое время.
▪ Составлена схема архитектуры со всеми сущностями и их связями в Miro
▪ Код слабо связан, функции не имеют побочных эффектов
▪ История коммитов осмысленная. По ней видно, в каком порядке решалась задача.
▪ Покрытие тестами >70%
Требования
▪Язык: Python
▪Результаты голосования должны храниться в базе данных. Мы обычно используем PostgreSQL и MongoDB, но можно выбрать любую другую.
▪Код нужно выложить на github (просьба не делать форк этого репозитория, чтобы не плодить плагиат)
▪Предоставить инструкцию по запуску приложения. В идеале (но не обязательно) – использовать контейнеризацию с возможностью запустить проект командой docker-compose up
▪Сервис должен отвечать на 8000 порту
Усложнения
▪ Написаны тесты (постарайтесь достичь покрытия в 70% и больше)
▪ Опишите, как изменится архитектура, если мы ожидаем большую нагрузку (Реализация не требуется)
▪ Опишите, как можно защититься от накруток (Реализация не требуется)
▪ Попробуйте оценить, какую нагрузку в RPS сможет выдержать ваш сервис
Что будет оцениваться
▪ Декомпозиция задачи (например, в виде вложенного списка подзадач)
▪ Архитектура решения
▪ Корректность реализации
▪ Подход к тестированию
▪ Понятность инструкций и документации
▪ Codestyle
▪ [Python] Typehints
@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18🔥4❤1
Forwarded from Анализ данных (Data analysis)
В этой статье я превратил некоторые из своих заметок в 20 вопросов для собеседований, которые охватывают структуры данных, основные концепции программирования и лучшие практики Python.
Интересно, что многие из этих вопросов также задаются на собеседованиях по Data Science.
@data_analysis_ml
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥2❤1
Условие:
Найти «счастливый» ip. Он считается счастливым, если сумма двух байтов с левой стороны равняются сумме двух байтов с правой стороны.
На вход функции всегда идёт строка с ipv4 адресом.
Пример:
is_happy_ip("255.255.255.255") -> True
is_happy_ip("0.0.0.1") -> False
is_happy_ip("101.78.170.9") -> True
P.S. 1 байт - число от 0 до 255
Делитесь своим решением в комментариях👇
def is_happy_ip(ip: str) -> bool:
g = ip.split('.')
return int(g[0])+int(g[1]) == int(g[2])+int(g[3])
@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🔥9❤2
Python есть встроенный отладчик под названием pdb. Это простая консольная утилита, которая обладает основной функциональностью для отладки кода. Но если вы ищете что-то более продвинутое, то стоит обратить внимание на ipdb – отладчик с функциональностью из IPython.
Проще всего вызвать отладчик pdb из кода, где вы работаете:
import pdb; pdb.set_trace()
Как только интерпретатор доберётся до этой строчки, запустится отладчик и в консоли будут доступны новые команды.
list()
Эта команда покажет часть кода, на выполнении которой сейчас находится интерпретатор. Можно передать два аргумента first и last для просмотра определённого участка кода. Если указать только first, то будет выведен код вокруг искомой строки.
up(p) и down(d)
Эти команды используются для передвижения по стеку вызовов. С их помощью можно отследить, откуда была вызвана текущая функция.
step() и next()
Другая пара не менее важных команд. С их помощью можно выполнять код построчно. Единственное различие между ними в том, что next() перейдёт к следующей строке вне зависимости от вызываемых функций, а step() перейдёт в вызванную функцию, если это возможно.
break()
Эта команда позволяет создавать брейкпоинты без внесений изменений в код. Ниже разберём этот этап более детально.
Краткий список команд отладчика pdb:
args() — выводит аргументы функции;
continue() или (cont) — продолжит выполнение до первого брейкпоинта или до завершения программы;
help() — выводит список доступных команд или подсказки по определённой команде;
jump() — перепрыгивает к выполнению указанной строчки кода;
list() — выводит исходный код программы вокруг выбранной строки;
expression() — выводит значение выражения;
pp — выводит значение в «красивом» виде;
quit или exit() — отменяет выполнение программы;
return() — завершает выполнение текущей функции.
@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍6❤3
Перегрузка операторов в Python – это возможность с помощью специальных методов в классах переопределять различные операторы языка. Имена таких методов включают двойное подчеркивание спереди и сзади.
Под операторами в данном контексте понимаются не только знаки +, -, *, /, обеспечивающие операции сложения, вычитания и др., но также специфика синтаксиса языка, обеспечивающая операции создания объекта, вызова объекта как функции, обращение к элементу объекта по индексу, вывод объекта и другое
На самом деле перегрузка операторов в пользовательских классах используется не так часто, если не считать конструктора. Но сам факт наличия такой особенности объектно-ориентированного программирования, требует отдельного рассмотрения темы.
Возможность перегрузки операторов обеспечивает схожесть пользовательского класса со встроенными классами Python. Ведь все встроенные типы данных Питона – это классы. В результате все объекты могут иметь одинаковые интерфейсы. Так если ваш класс предполагает обращение к элементу объекта по индексу, например a[0], то это можно обеспечить.
Пусть будет класс-агрегат B, содержащий в списке объекты класса A:
class A:
def __init__(self, arg):
self.arg = arg
def __str__(self):
return str(self.arg)
class B:
def __init__(self, *args):
self.aList = []
for i in args:
self.aList.append(A(i))
group = B(5, 10, 'abc')
Чтобы получить элемент списка, несомненно, мы можем обратиться по индексу к полю aList:
print(group.aList[1])
Однако куда интереснее извлекать элемент по индексу из самого объекта, а не из его поля:
class B:
def __init__(self, *args):
self.aList = []
for i in args:
self.aList.append(A(i))
def __getitem__(self, i):
return self.aList[i]
group = B(5, 10, 'abc')
print(group.aList[1]) # выведет 10
print(group[0]) # 5
print(group[2]) # abc
Это делает объекты класса B похожими на объекты встроенных в Python классов-последовательностей (списков, строк, кортежей). Здесь метод __getitem__() перегружает операцию извлечения элемента по индексу. Другими словами, этот метод вызывается, когда к объекту применяется операция извлечения элемента: объект[индекс].
Бывает необходимо, чтобы объект вел себя как функция. Это значит, если у нас есть объект a, то мы можем обращаться к нему в нотации функции, т. е. ставить после него круглые скобки и даже передавать в них аргументы:
a = A()
a()
a(3, 4)
Метод
__call__()
автоматически вызывается, когда к объекту обращаются как к функции. Например, здесь во второй строке произойдет вызов метода __call__() некогоКласса:объект = некийКласс()
объект([возможные аргументы])
Пример:
class Changeable:
def __init__(self, color):
self.color = color
def __call__(self, newcolor):
self.color = newcolor
def __str__(self):
return "%s" % self.color
canvas = Changeable("green")
frame = Changeable("blue")
canvas("red")
frame("yellow")
print(canvas, frame)
В этом примере с помощью конструктора класса при создании объектов устанавливается их цвет. Если требуется его поменять, то достаточно обратиться к объекту как к функции и в качестве аргумента передать новый цвет. Такой обращение автоматически вызовет метод __call__(), который, в данном случае, изменит атрибут color объекта.
@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👍27❤3🔥2
▪Преобразование типов - это преобразование объекта из одного типа данных в другой тип данных.
▪Неявное преобразование типов автоматически выполняется интерпретатором Python.
▪Python позволяет избежать потери данных в неявном преобразовании типов.
▪Явное преобразование типов также называется приведением типов, типы данных объекта преобразуются с использованием предопределенной функции.
▪При приведении типов может произойти потеря данных, поскольку мы приводим объект к определенному типу данных.
Что такое аннотация типов?
В простейшем случае аннотация содержит непосредственно ожидаемый тип. Аннотации для переменных пишут через двоеточие после идентификатора. После этого может идти инициализация значения. Например
price: int = 5
Параметры функции аннотируются так же как переменные, а возвращаемое значение указывается после стрелки -> и до завершающего двоеточия. Например def indent_right(s: str, width: int) -> str:.
@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14⚡1❤1🔥1
✔️Задача | #Junior
Условие:
Вам нужно написать функцию, которая будет обрезать строку до определённой длины и добавлять в конец троеточие. Если текст равен max_len или max_len больше длины текста, то ничего не меняем.
Пример:
❗️ Делитесь своим решением в комментариях👇
@python_job_interview
Условие:
Вам нужно написать функцию, которая будет обрезать строку до определённой длины и добавлять в конец троеточие. Если текст равен max_len или max_len больше длины текста, то ничего не меняем.
Пример:
text = "Lorem Ipsum is simply dummy text"
cut_str(text, max_len=12) -> Lorem Ipsum...
cut_str(text, max_len=40) -> Lorem Ipsum is simply dummy text
@python_job_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥2❤1
✔️Задача | #Middle
Реализуйте итератор колоды карт (52 штуки) CardDeck. Каждая карта представлена в виде строки типа «2 Пик». При вызове функции next() будет представлена следующая карта. По окончании перебора всех элементов возникнет ошибка StopIteration.
Ответ
Чтобы реализовать протокол итератора требуется внедрить 2 метода:
Результат выполнения
@python_job_interview
Реализуйте итератор колоды карт (52 штуки) CardDeck. Каждая карта представлена в виде строки типа «2 Пик». При вызове функции next() будет представлена следующая карта. По окончании перебора всех элементов возникнет ошибка StopIteration.
Ответ
Чтобы реализовать протокол итератора требуется внедрить 2 метода:
__iter__() и __next__()
. Для понимания того, что коллекция иссякла, не стоить забывать и про ее длину (52).class CardDeck:
def __init__(self):
self.length = 52
self.index = 0
self.__SUITS = ['Пик', 'Бубей', 'Червей', 'Крестей']
self.__RANKS = [*range(2, 11), 'J', 'Q', 'K', 'A']
def __len__(self):
return self.length
def __next__(self):
if self.index >= self.length:
raise StopIteration
else:
suit = self.__SUITS[self.index // len(self.__RANKS)]
rank = self.__RANKS[self.index % len(self.__RANKS)]
self.index += 1
return f'{rank} {suit}'
def __iter__(self):
return self
deck = CardDeck()
while True:
print(next(deck))
2 Пик
3 Пик
4 Пик
…
K Крестей
A Крестей
StopIteration
@python_job_interview
👍27🔥4❤1
Быть DevOps специалистом в 2023 году — значит обладать самой востребованной ит-профессией. Зайдите в гугл и убедитесь - на рынке нехватка спецов, больше 5000 компаний ищут DevOps разработчиков, а средняя зарплата в DevOps — 250 000 рублей.
Стоит ли читать книги или покупать курсы? Однозначно Нет.
С каналом DevOps school вы за пару месяц освоите профессию.
В канале автор понятным языком рассказывает, как быстро освоить ключевые навыки на практике, почему Devops - золотая ниша в ит какие тренды изучать в 2023 году
Подписывайтесь: @DevOPSitsec
Стоит ли читать книги или покупать курсы? Однозначно Нет.
С каналом DevOps school вы за пару месяц освоите профессию.
В канале автор понятным языком рассказывает, как быстро освоить ключевые навыки на практике, почему Devops - золотая ниша в ит какие тренды изучать в 2023 году
Подписывайтесь: @DevOPSitsec
👎11👍5🔥2❤1
⚡️ Задача с собеседования |: #Junior
Условие:
Ваша задача — написать функцию, которая находит сумму всех цифр в числе. На вход также могут пойти и числа меньше нуля — их стоит переводить в неотрицательное числа.
Пример:
Знак "_" в числах может использоваться для упрощения чтения пользователем.
👉 Пишите ваше решение в комментариях👇
@python_job_interview
Условие:
Ваша задача — написать функцию, которая находит сумму всех цифр в числе. На вход также могут пойти и числа меньше нуля — их стоит переводить в неотрицательное числа.
Пример:
1234 → 10
-9876 → 30
7013 → 11
100001 → 2
Знак "_" в числах может использоваться для упрощения чтения пользователем.
1_000_000
— это то же самое, что и 1000000
👉 Пишите ваше решение в комментариях👇
@python_job_interview
👍4🔥3❤1
⚡️ Задача с собеседования |: #Junior
Условие
Числа Фибоначчи представляют последовательность, получаемую в результате сложения двух предыдущих элементов.
Начинается коллекция с чисел 1 и 1.
Она достаточно быстро растет, поэтому вычисление больших значений занимает немало времени.
Создайте функцию
Для реализации этой функции потребуется обратиться к инструкции
Она не сохраняет в оперативной памяти огромную последовательность, а дает возможность “доставать” промежуточные результаты по одному.
Необходимо превратить функцию в генератор при помощи инструкции yield, чтобы вычисления осуществлялись не сразу, а по мере надобности.
Решение
👉 Пишите свое решение в комментариях👇
@python_job_interview
Условие
Числа Фибоначчи представляют последовательность, получаемую в результате сложения двух предыдущих элементов.
Начинается коллекция с чисел 1 и 1.
Она достаточно быстро растет, поэтому вычисление больших значений занимает немало времени.
Создайте функцию
fib(n)
, генерирующую n чисел Фибоначчи с минимальными затратами ресурсов.Для реализации этой функции потребуется обратиться к инструкции
yield
. Она не сохраняет в оперативной памяти огромную последовательность, а дает возможность “доставать” промежуточные результаты по одному.
Необходимо превратить функцию в генератор при помощи инструкции yield, чтобы вычисления осуществлялись не сразу, а по мере надобности.
Решение
def fib(n):
fib0 = 1
yield fib0
fib1 = 1
yield fib1
for i in range(n - 2):
fib0, fib1 = fib1, fib0 + fib1
yield fib1
# Тест
for num in fib(112121):
pass
print(num)
👉 Пишите свое решение в комментариях👇
@python_job_interview
👍7❤6🔥1
⚡️ Задача
Требуется создать csv-файл
– № - номер по порядку (от 1 до 300);
– Секунда – текущая секунда на вашем ПК;
– Микросекунда – текущая миллисекунда на часах.
На каждой итерации цикла искусственно приостанавливайте скрипт на 0,01 секунды.
Для работы с файлами подобного текстового формата потребуется встроенная в Python библиотека csv.
Решение
В итоге создастся требуемый файл. Приведем первые строки его содержимого:
Содержимое файла rows_300.csv
👉 Пишите ваше решение в комментариях👇
@python_job_interview
Требуется создать csv-файл
«rows_300.csv»
со следующими столбцами:– № - номер по порядку (от 1 до 300);
– Секунда – текущая секунда на вашем ПК;
– Микросекунда – текущая миллисекунда на часах.
На каждой итерации цикла искусственно приостанавливайте скрипт на 0,01 секунды.
Для работы с файлами подобного текстового формата потребуется встроенная в Python библиотека csv.
Решение
import csv
import datetime
import time
with open('rows_300.csv', 'w', encoding='utf-8', newline='') as f:
writer = csv.writer(f)
writer.writerow(['№', 'Секунда ', 'Микросекунда'])
for line in range(1, 301):
writer.writerow([line, datetime.datetime.now().second, datetime.datetime.now().microsecond])
time.sleep(0.01)
В итоге создастся требуемый файл. Приведем первые строки его содержимого:
Содержимое файла rows_300.csv
№,Секунда ,Микросекунда
1,51,504807
2,51,515807
3,51,526819
4,51,537817
5,51,548800
6,51,558817
…
👉 Пишите ваше решение в комментариях👇
@python_job_interview
👍7🔥3🥰1
❓ Когда применяются ленивые вычисления и в чем их логика
Ленивые вычисления предполагают, что не нужно ничего делать до тех пор, пока в этом нет необходимости. Так, если мы не обратились к свойству класса (которое определяется некими математическими операциями, например), то не нужно заранее его рассчитывать. На этом базируется, в том числе, логика генераторов. Многие итераторы также являются ленивыми. Это не просто удобно, но позволяет экономить память и время на вычисление.
Нагляднее всего можно понять преимущество ленивых вычислений (и итераторов) на следующем примере.
# Создадим итерабельный объект
Функция
Если вы рискнете преобразовать этот массив чисел в список, то случится одно из двух: либо выведется ошибка о нехватке памяти на компьютере, либо очень-очень долго будет формироваться список всех объектов.
@python_job_interview
Ленивые вычисления предполагают, что не нужно ничего делать до тех пор, пока в этом нет необходимости. Так, если мы не обратились к свойству класса (которое определяется некими математическими операциями, например), то не нужно заранее его рассчитывать. На этом базируется, в том числе, логика генераторов. Многие итераторы также являются ленивыми. Это не просто удобно, но позволяет экономить память и время на вычисление.
Нагляднее всего можно понять преимущество ленивых вычислений (и итераторов) на следующем примере.
# Создадим итерабельный объект
nums = range(1, 12121212112)
nums[10543210010]
10543210011 # Практически моментальный вывод
list(nums)
MemoryError
Функция
range()
– ленивая. Она заранее не формирует последовательность из гигантского количества чисел. А когда мы обращаемся к некому ее элементу по индексу (это разрешено, так как она создает итерабельный объект), он выводится почти сразу.Если вы рискнете преобразовать этот массив чисел в список, то случится одно из двух: либо выведется ошибка о нехватке памяти на компьютере, либо очень-очень долго будет формироваться список всех объектов.
@python_job_interview
👍17🔥3❤2
❓Что такое дескрипторы данных?
Очень часто переменные, инициализируемые в классе, являются однотипными. Например, есть класс Employee (сотрудник), принимающий параметры: имя, фамилия, отчество, должность. Все они являются строками. Следовательно, прежде чем создать экземпляр класса, нужно проверить, что пользователь ввел строки. А для этого потребуются сеттеры, проверяющие тип вводимых параметров. В итоге, мы 4 раза повторим код проверки. Нарушается принцип DRY (don't repeat yourself).
Для таких ситуаций удобно использовать дескрипторы (они, к слову, широко применяются во фреймворке Django при создании моделей).
Дескриптор - такой атрибут объекта, поведение которого переопределяется специальными методами. Проще говоря, доступ к какому-то свойству экземпляра можно переопределить с учетом дополнительных проверок. Если делать эти верификации без дескрипторов, то один и тот же код начнет повторяться.
Существует 4 метода протокола дескрипторов:
Если применяется только метод
Покажем использование дескрипторов на вышеупомянутом примере.
Пример – IDE
---
# Создаем класс с протоколами дескриптора
# Инициализируем свойства с учетом требуемых проверок
# Тесты
Результат выполнения
---
ValueError: Нужно предоставить строку
ValueError: Минимум две буквы в атрибуте требуется
@python_job_interview
Очень часто переменные, инициализируемые в классе, являются однотипными. Например, есть класс Employee (сотрудник), принимающий параметры: имя, фамилия, отчество, должность. Все они являются строками. Следовательно, прежде чем создать экземпляр класса, нужно проверить, что пользователь ввел строки. А для этого потребуются сеттеры, проверяющие тип вводимых параметров. В итоге, мы 4 раза повторим код проверки. Нарушается принцип DRY (don't repeat yourself).
Для таких ситуаций удобно использовать дескрипторы (они, к слову, широко применяются во фреймворке Django при создании моделей).
Дескриптор - такой атрибут объекта, поведение которого переопределяется специальными методами. Проще говоря, доступ к какому-то свойству экземпляра можно переопределить с учетом дополнительных проверок. Если делать эти верификации без дескрипторов, то один и тот же код начнет повторяться.
Существует 4 метода протокола дескрипторов:
get__()
- получить значение свойства;set__()
- задать значение;delete__()
- удалить атрибут;set_name__()
- присвоить имя свойству (появился в Питоне версии 3.6).Если применяется только метод
__get__(),
то мы имеем дело с дескриптором без данных, а если есть еще и __set__()
, то речь будет идти о дескрипторе данных.Покажем использование дескрипторов на вышеупомянутом примере.
Пример – IDE
---
# Создаем класс с протоколами дескриптора
class StringChecker:
# Получаем доступ к свойству
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
# Меняем свойство
def __set__(self, instance, str_value):
if not isinstance(str_value, str):
raise ValueError('Нужно предоставить строку')
elif len(str_value) < 2:
raise ValueError('Необходимо минимум 2 буквы')
instance.__dict__[self.name] = str_value
# Задаем имя свойстваdef __set_name__(self, owner, name):
self.name = name
class Employee:
# Определяем атрибуты (их может быть любое количество)
name = StringChecker()
surname = StringChecker()
patronymic = StringChecker()
post = StringChecker()
# Инициализируем свойства с учетом требуемых проверок
def __init__(self, name, surname, patronymic, post):
self.name = name
self.surname = surname
self.patronymic = patronymic
self.post = post
# Тесты
director = Employee('Иван', 'Николаевич', 'Прогин', 'Директор')
print(director.__dict__)
director.name = 1
director.name = 'A'
Результат выполнения
---
{'name': 'Иван', 'surname': 'Николаевич', 'patronymic': 'Прогин', 'post': 'Директор'}
ValueError: Нужно предоставить строку
ValueError: Минимум две буквы в атрибуте требуется
@python_job_interview
👍21🔥3❤1
⚡️ Задача
Инструкция yield позволяет создавать генераторы.
Инструкция
В отличие от объявления return в функции, где возвращается один объект, yield при каждом вызове функции генерирует новый объект.
Фактически это дает возможность использовать генераторы в циклах.
Самая важная причина применения такой инструкции - экономия памяти, когда не требуется сохранять всю последовательность, а можно получать ее элементы по одному.
Ученик написал генератор
Сократите код функции.
Код
---
Конструкция
Решение - IDE
@python_job_interview
Инструкция yield позволяет создавать генераторы.
Инструкция
yield
позволяет создавать генераторы. В отличие от объявления return в функции, где возвращается один объект, yield при каждом вызове функции генерирует новый объект.
Фактически это дает возможность использовать генераторы в циклах.
Самая важная причина применения такой инструкции - экономия памяти, когда не требуется сохранять всю последовательность, а можно получать ее элементы по одному.
Ученик написал генератор
show_letters(some_str)
, выводящий все символы строки на печать, но только в том случае, если они являются буквами (остальные игнорируются). Сократите код функции.
Код
---
def show_letters(some_str):
clean_str = ''.join([letter for letter in some_str if letter.isalpha()])
for symbol in clean_str:
yield symbol
Конструкция
yield
from позволяет полностью убрать цикл из функции. Она "вкладывает" один генератор внутрь другого, что дает возможность управления несколькими генераторами.Решение - IDE
def show_letters(some_str):
yield from ''.join([letter for letter in some_str if letter.isalpha()])
random_str = show_letters('A!sdf 09 _ w')
print(next(random_str))
print(next(random_str))
Результат выполнения
A
s
@python_job_interview
👍15❤2👎1🔥1
⚡️ Задача: найдите первый неповторяющийся символ в строке, выполнив только один обход
Для заданной строки найдите в ней первый неповторяющийся символ, выполнив только один ее обход.
Например,
Простым решением было бы сохранить количество каждого символа в словаре или списке, пройдя его один раз.
Затем еще раз просмотреть строку, чтобы найти первый символ, имеющий значение 1. Временная сложность этого решения равна O(n), где n длина входной строки. Проблема с этим решением заключается в том, что строка проходится дважды, что нарушает ограничения программы.
Мы можем решить эту задачу за один обход строки. Идея состоит в том, чтобы использовать словарь для хранения количества каждого отдельного символа и индекса его первого или последнего вхождения в строку. Затем пройтись по словарю и найти символ с минимальным индексом строки.
👉 Пишите ваше решение в комментариях👇
@python_job_interview
Для заданной строки найдите в ней первый неповторяющийся символ, выполнив только один ее обход.
Например,
Input:
string is ABCDBAGHC
Output:
первый неповторяющийся символ: D
Простым решением было бы сохранить количество каждого символа в словаре или списке, пройдя его один раз.
Затем еще раз просмотреть строку, чтобы найти первый символ, имеющий значение 1. Временная сложность этого решения равна O(n), где n длина входной строки. Проблема с этим решением заключается в том, что строка проходится дважды, что нарушает ограничения программы.
Мы можем решить эту задачу за один обход строки. Идея состоит в том, чтобы использовать словарь для хранения количества каждого отдельного символа и индекса его первого или последнего вхождения в строку. Затем пройтись по словарю и найти символ с минимальным индексом строки.
# Функция поиска первого неповторяющегося символа в
# строк
е, выполнив только один ее обход
def findNonRepeatingChar(s):
# Базовый вариант
if not s:
return -1
# словарь # для хранения количества символов и индекса их
# последнее вхождение в строку
d = {}
for index, char in enumerate(s):
frequency, prevIndex = d.get(char, (0, index))
d[char] = (frequency + 1, index)
# хранит индекс первого неповторяющегося символа
min_index = -1
# Проходим словарь и находим символ
for key, values in d.items():
count, firstIndex = values
if count == 1 and (min_index == -1 or firstIndex < min_index):
min_index = firstIndex
return min_index
if __name__ == '__main__':
s = 'ABCDBAGHC'
index = findNonRepeatingChar(s)
if index != -1:
print('первый неповторяющийся символ: ', s[index])
else:
print('Таких символов нет')
👉 Пишите ваше решение в комментариях👇
@python_job_interview
👍14❤4🥰2