.py
#ti 2/∞ техническое интервью после тестового задания позвали на интервью созвон вели 2 разраба рассказали про компанию, показали продукт, объяснили чем предстоит заниматься, минимально спросили про опыт и учебу во время разговора вскользь поговорили про…
#hw
дз по курсам
codereview у gpt.
Попробовал подход test-first
лучшее
- параметризация(разные кейсы)
- monkeypatch В кейсе внутри функции данные с консоли input(), в автотестах перехватываешь built in input и меняешь на возврат нужных параметров
дз по курсам
codereview у gpt.
Попробовал подход test-first
@pytest.mark.parametrize(
"num, result", [
(0, None),
(1000, 'millennium'),
(100000000000000, 'millennium'),
(-20000, 'millennium'),
(-19999, None)
]
)
def test_is_multiple_of_1000(num, result):
assert is_multiple_of_1000(num) == result
@pytest.mark.parametrize(
"input_data, result", [
(60, 'restaurant'),
(30, 'cafe'),
(5, 'home'),
(-20000, None),
(0, None),
]
)
def test_get_venue_by_guest_count(monkeypatch, input_data, result):
monkeypatch.setattr('builtins.input', lambda _: input_data)
guest_count = get_user_input()
assert get_venue_by_guest_count(guest_count) == result
@pytest.mark.parametrize(
"list_in, result", [
([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [-2, -4, -6, -8, -10, -12, -14, -16, -18, -20]),
([-3, -5, 2, 13, -100, 1, 0], [6, 10, -4, -26, 200, -2, 0]),
([], []),
([0], [0]),
([1], [-2])
]
)
def test_multiply_by_neg2(list_in, result):
assert multiply_by_neg2(list_in) == result
@pytest.mark.parametrize(
"num_list, even_num_count", [
([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5),
([-3, -5, 2, 13, -100, 1, 0], 3),
([], 0),
([0], 1),
([1, 3, 13, 17], 0)
]
)
def test_get_even_num_count(num_list, even_num_count):
assert get_even_num_count(num_list) == even_num_count
@pytest.mark.parametrize("input_dict, expected_output", [
({'test': 'test_value', 'europe': 'eur', 'dollar': 'usd', 'ruble': 'rub'},
{'test4': 'test_value', 'europe6': 'eur', 'dollar6': 'usd', 'ruble5': 'rub'}),
({'key': 'value'}, {'key3': 'value'}),
({'empty': '', 'long_key': 'value'}, {'empty5': '', 'long_key8': 'value'}),
({'a': 'alpha', 'b': 'beta'}, {'a1': 'alpha', 'b1': 'beta'})
])
def test_add_dict_key_len_into_key(input_dict, expected_output):
assert add_dict_key_len_into_key(input_dict) == expected_output
# Параметризованные тесты для функции shift_left
@pytest.mark.parametrize("input_list, expected_output", [
([1, 2, 3, 4, 5], [2, 3, 4, 5, 1]), # Простой случай
([7, 8, 9], [8, 9, 7]), # Случай с 3 элементами
([10], [10]), # Случай с одним элементом
([], []), # Случай с пустым списком
([1, 2], [2, 1]), # Случай с двумя элементами
])
def test_num_list_shift(input_list, expected_output):
assert num_list_shift(input_list) == expected_output
@pytest.mark.parametrize("fib_list_count, expected_output", [
(1, [0]), # 1-е число Фибоначчи
(5, [0, 1, 1, 2, 3]), # [0, 1, 1, 2, 3] -> [1, 1, 2, 3, 0]
(8, [0, 1, 1, 2, 3, 5, 8, 13]), # [0, 1, 1, 2, 3, 5, 8, 13] -> [1, 1, 2, 3, 5, 8, 13, 0]
(15, [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]), # [0, 1, ..., 377] -> [1, 1, ..., 0]
(30, [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657,
46368, 75025, 121393, 196418, 317811, 514229]) # [0, 1, ..., 832040] -> [1, 1, ..., 0]
])
def test_get_fibonacci_sequence(fib_list_count, expected_output):
assert get_fibonacci_sequence(fib_list_count) == expected_output
лучшее
- параметризация(разные кейсы)
- monkeypatch В кейсе внутри функции данные с консоли input(), в автотестах перехватываешь built in input и меняешь на возврат нужных параметров
.py
#hw дз по курсам codereview у gpt. Попробовал подход test-first @pytest.mark.parametrize( "num, result", [ (0, None), (1000, 'millennium'), (100000000000000, 'millennium'), (-20000, 'millennium'), (-19999, None)…
#hw
в какую сторону библиотека decimal округляет по дефолту? Если в ответе нужна точность 6 цпз, какую указывать в рассчетах?
#Для заданного числа N составьте программу вычисления суммы
#S=1+1/2+1/3+1/4+...+1/N, где N – натуральное число.
def get_harmonic_series_sum(n):
if n <= 0:
return False
if n == 1:
return Decimal(1)
harmonic_sum = reduce(lambda x, a: x + (Decimal(1) / Decimal(a)), range(1, n + 1))
return harmonic_sum.quantize(Decimal('0.000001'), ROUND_FLOOR)
@pytest.mark.parametrize(
"num, exp_res", (
[1, Decimal(1.0)],
[2, Decimal(1.5)],
[3, Decimal('1.833333')],
[10, Decimal('2.928968')],
[100, Decimal('5.187377')],
[0, False],
[-5, False]
)
)
def test_get_harmonic_series(num, exp_res):
assert get_harmonic_series_sum(num) == exp_res
в какую сторону библиотека decimal округляет по дефолту? Если в ответе нужна точность 6 цпз, какую указывать в рассчетах?
#hw 5 lesson
"""
Для каждого натурального числа в промежутке от m до n вывести все делители,
кроме единицы и самого числа. m и n вводятся с клавиатуры.
"""
def get_interval_dividers(x, y):
dividers_dict = {}
for el in range(x, y + 1):
dividers_dict[el] = []
for divider in range(2, int(sqrt(el)) + 1):
if el % divider == 0:
dividers_dict[el].append(divider)
if divider != el // divider: # Добавляем сопряженный делитель
dividers_dict[el].append(el // divider)
return dividers_dict
def get_interval():
interval = list(map(int, input('press x y').strip().split(' ')))
if len(interval) != 2 or interval[0] >= interval[1]:
raise ValueError
return interval
def run_interval_dividers_script():
intervals = get_interval()
pprint.pprint(get_interval_dividers(*intervals))
"""
Создать список поездов. Структура словаря: номер поезда,
пункт и время прибытия, пункт и время отбытия. Вывести все сведения о поездах,
время пребывания в пути которых превышает 7 часов 20 минут.
"""
cities_us = [
"New York",
"Los Angeles",
"Chicago",
"Houston",
"Phoenix",
"Philadelphia",
"San Antonio",
"San Diego",
"Dallas",
"San Jose",
"Austin",
"Jacksonville",
"Fort Worth",
"Columbus",
"San Francisco",
"Charlotte",
"Indianapolis",
"Seattle",
"Denver",
"Washington, D.C.",
"Boston"
]
def generate_train_schedule(train_count):
trains_schedule = {}
now = datetime.datetime.now()
for _ in range(0, train_count):
arrival_time = datetime.datetime.combine(now.date(), datetime.time(randint(0, 23), randint(0, 59)))
departure_time = arrival_time + datetime.timedelta(hours=randint(1, 23), minutes=randint(1, 59))
trains_schedule[randint(1000, 9999)] = {
'arrival': {
'location': random.choice(cities_us),
'time': arrival_time},
'departure': {
'location': random.choice(cities_us),
'time': departure_time
}
}
return trains_schedule
def get_long_way_trips(trains_schedule):
return {
train_num for train_num in trains_schedule if
(trains_schedule[train_num]['departure']['time'] - trains_schedule[train_num]['arrival'][
'time']) > datetime.timedelta(hours=7, minutes=20)
}
#git
сок про git
https://proglib.io/p/git-for-half-an-hour
сок про git
https://proglib.io/p/git-for-half-an-hour
Общий конфиг, в одной команде, username, email, ссылки для репозиториев(git remote -v) и их названия и тд
git config --list
#tt 3/∞ тестовое задание
pythonDev 100к
Команда состоит из 5 человек
Компания заниматься (CRM, СКЛАД,
ПЛАНИРОВЩИК, HELPDESK, ЭДО,
УЧЁТ МАТЕРИАЛЬНЫХ ЦЕННОСТЕЙ, ПУТЕВЫЕ ЛИСТЫ, ОТЧЁТНОСТЬ, УПРАВЛЕНИЕ ПЕРСОНАЛОМ)
Задание: Реализация полосы чтения –> загрузки сообщений с почты. Необходимо продумать
гибкий функционал для импортирования в систему сообщений из “yandex.ru”,
“gmail.com”, “mail.ru”. Модели в django, прогресс бар, показывающий сколько сообщений проверено (чтобы найти последнее полученное и очертить линию получения новых сообщений в бд)
создал костяк, настроил базу данных, сверстал фронт, настроил imap
при нахождении последнего полученного сообщений мы получаем массив с uid сообщений, некоторые из них уже могли удалить поэтому это по сути упорядоченный массив из айдишников но идущих возможно не по порядку. Для поиска идеально подошел бинарный поиск.
далее настроил websocket соединение, настроил асинхронное поведение. Скрипт по сути сначала проводит аутентификацию и далее рендерит страницу которая через js запускает цепочку обработки через WS.
задание решалось очень долго, около 18 дней, время выделял во время марафона на основной работе. Нужно более структурицизованная и последовательная разработка. В этот раз тесты и оптимизацию не делал. Потратил очень много времени на тз, учитывая что делал для себя и глянут его мельком, для первого проекта на django считаю солидно. Type hints отсутствуют, обработка ошибок есть но посредственная.
https://github.com/nk-knvlv/comsoftlab
pythonDev 100к
Команда состоит из 5 человек
Компания заниматься (CRM, СКЛАД,
ПЛАНИРОВЩИК, HELPDESK, ЭДО,
УЧЁТ МАТЕРИАЛЬНЫХ ЦЕННОСТЕЙ, ПУТЕВЫЕ ЛИСТЫ, ОТЧЁТНОСТЬ, УПРАВЛЕНИЕ ПЕРСОНАЛОМ)
Задание: Реализация полосы чтения –> загрузки сообщений с почты. Необходимо продумать
гибкий функционал для импортирования в систему сообщений из “yandex.ru”,
“gmail.com”, “mail.ru”. Модели в django, прогресс бар, показывающий сколько сообщений проверено (чтобы найти последнее полученное и очертить линию получения новых сообщений в бд)
создал костяк, настроил базу данных, сверстал фронт, настроил imap
при нахождении последнего полученного сообщений мы получаем массив с uid сообщений, некоторые из них уже могли удалить поэтому это по сути упорядоченный массив из айдишников но идущих возможно не по порядку. Для поиска идеально подошел бинарный поиск.
далее настроил websocket соединение, настроил асинхронное поведение. Скрипт по сути сначала проводит аутентификацию и далее рендерит страницу которая через js запускает цепочку обработки через WS.
задание решалось очень долго, около 18 дней, время выделял во время марафона на основной работе. Нужно более структурицизованная и последовательная разработка. В этот раз тесты и оптимизацию не делал. Потратил очень много времени на тз, учитывая что делал для себя и глянут его мельком, для первого проекта на django считаю солидно. Type hints отсутствуют, обработка ошибок есть но посредственная.
https://github.com/nk-knvlv/comsoftlab
.py
#tt 3/∞ тестовое задание pythonDev 100к Команда состоит из 5 человек Компания заниматься (CRM, СКЛАД, ПЛАНИРОВЩИК, HELPDESK, ЭДО, УЧЁТ МАТЕРИАЛЬНЫХ ЦЕННОСТЕЙ, ПУТЕВЫЕ ЛИСТЫ, ОТЧЁТНОСТЬ, УПРАВЛЕНИЕ ПЕРСОНАЛОМ) Задание: Реализация полосы чтения –> загрузки…
#alg Бинарный поиск
Чтобы по настоящему знать этот алгоритм, нужно понимать не просто концепцию деления общей массы напополам с рекурсией, а какие частные случаи обрабатываются
Чтобы по настоящему знать этот алгоритм, нужно понимать не просто концепцию деления общей массы напополам с рекурсией, а какие частные случаи обрабатываются
def binary_search(numbers_list, target_num):
if not numbers_list: # пустой список
return -1
if len(numbers_list) == 1: # один элемент важно проверять на соответствие искомому
if numbers_list[0] == target_num:
return 0
else:
return -1
low = 0
high = len(numbers_list) - 1
while low <= high: #понять почему допускается = вместо строгого <
mid = (low + high) // 2 # как в python работает деление, почему 5//2=2, но -5//2=-3
if numbers_list[mid] == target_num: # должна ли проверка находиться до очередного деления mid или после
return mid
if numbers_list[mid] > target_num:
high = mid - 1 # почему уменьшаем
else:
low = mid + 1 # и увеличиваем
return -1
#alg bubble sort
def bubble_sort(num_list: list[int]) -> list[int]:
# border cases как [ ], [1], обработает range, отдельно писать не нужно
is_swap = True
while is_swap:
is_swap = False
for i in range(len(num_list)-1):
if num_list[i] > num_list[i + 1]:
num_list[i], num_list[i + 1] = num_list[i + 1], num_list[i] # python позволяет 1 строчкой менять элементы местами вместо temp переменной, техника называется кортежный своп(tuple swap)
is_swap = True
return num_list
#alg dumb sort - прадед bubble sort, не боевой алгоритм. Используется как пример "неэффективного алгоритма".
def dumb_sort(num_list: list[int]) -> list[int]:
is_swap = True
while is_swap:
is_swap = False
for i in range(len(num_list)-1):
if num_list[i] > num_list[i + 1]:
num_list[i], num_list[i + 1] = num_list[i + 1], num_list[i]
is_swap = True
continue
return num_list
#alg shake sort - улучшенный bubble sort, после вспытия большего поворачивает в обратную сторону перенося наименьшее значение в начало
def shake_sort(num_list: list[int]) -> list[int]:
if len(num_list) < 2:
return num_list
low = 0
high = len(num_list) - 1
while low < high:
for i in range(low, high):
if num_list[i] > num_list[i + 1]:
num_list[i], num_list[i + 1] = num_list[i + 1], num_list[i]
high -= 1
for i in range(high, low, -1):
if num_list[i] < num_list[i - 1]:
num_list[i], num_list[i - 1] = num_list[i - 1], num_list[i]
low += 1
return num_list
#alg even odd sort - улучшенный bubble sort, поочередно проходящий по парам начинающимся с четного индекса, на следующей итерации по парам нач с нечетных индексов.
def even_odd_sort(num_list: list[int]) -> list[int]:
if len(num_list) < 2:
return num_list
even_odd_switch = 0
low = 0
high = len(num_list) - 1
pure_sort_passing = []
while len(pure_sort_passing) < 2:
pure_sort_passing.append(even_odd_switch)
for i in range(low + even_odd_switch, high, 2):
if num_list[i] > num_list[i + 1]:
num_list[i], num_list[i + 1] = num_list[i + 1], num_list[i]
if even_odd_switch in pure_sort_passing:
pure_sort_passing.remove(even_odd_switch)
even_odd_switch = 1 - even_odd_switch # swap even to odd and vice versa.
return num_list
#alg comb sort - сотрировка расческой
def comb_sort(num_list: list[int]) -> list[int]:
if len(num_list) < 2:
return num_list
# Общепризнанный оптимальный фактор уменьшения
reduction_factor = 1.247
count = len(num_list)
between_el_dist = count
is_swap = True
# если проходы с расстоянием больше 1 закончены, нужна финальная проверка классическим пузырьком
# которая вызывается условием or between_el_dist > 1
while is_swap or between_el_dist > 1:
between_el_dist = max(1, int(between_el_dist // reduction_factor))
high = count - between_el_dist
is_swap = False
for i in range(0, high):
if num_list[i] > num_list[i + between_el_dist]:
num_list[i], num_list[i + between_el_dist] = num_list[i + between_el_dist], num_list[i]
is_swap = True
return num_list
#alg insertion_sort - сортировка вставками
def insertion_sort(num_list: list[int]) -> list[int]:
# моржовый оператор := позволяет внутри выражения присвоить переменную для дальнейшего использования
if (length := len(num_list)) < 2:
return num_list
for i in range(1, length):
for j in range(i, 0, -1):
if num_list[j - 1] > num_list[j]:
num_list[j], num_list[j - 1] = num_list[j - 1], num_list[j]
else:
break
return num_list
#alg selection_sort - сортировка выбором
def selection_sort(num_list: list[int]) -> list[int]:
if (length := len(num_list)) < 2:
return num_list
for i in range(length):
current_max_index = 0
for j in range(length - i):
if num_list[j] > num_list[current_max_index]:
current_max_index = j
# no swap if index don't changed
if current_max_index != length - i - 1:
num_list[length - i - 1], num_list[current_max_index] = num_list[current_max_index], num_list[length - i - 1]
return num_list
внутри строк данные можно быстро редактировать с помощью (: + оператор ) перед выводом:
#указать количество цифр после запятой
price = 200.2010
digits_count_str = f'{price:.2f}' # Output 200.20
# Целые числа: :d Этот кейс мне кажется бесполезным, если убрать :d то
# вывод не поменяется, а семантику несет название переменной
int_str = f'{value:d}'
#Проценты: :.2% супер полезное свойство, переводит десятичную дробь в проценты с указанием знаков после запятой
percent = 0.123132
perc_str = f'{percent:.3%}' Output '12.313%'
# Отступы при выводе
# Пример с выравниванием влево
value = "Привет"
leveling_str = f'{value:<10}' # "Привет "
print(leveling_str)
# Пример с выравниванием вправо
value = "Мир"
leveling_str = f'{value:>10}' # " Мир"
print(leveling_str)
# Пример с центровкой
value = "Python"
leveling_str = f'{value:^10}' # " Python "
print(leveling_str)
# Пример с числом
value = 42
leveling_str = f'{value:<5}' # "42 "
print(leveling_str)
#alg quick_sort - быстрая сортировка (сортировка Хоара). Выделяем опорный элемент pivot, относительно которого строим рекурсию, используем функцию для участков слева и справа от опорного, и так до мельчайших отсортированных списков.
def partition(left, right, num_list):
pivot_index = random.randint(left, right)
pivot_value = num_list[pivot_index]
num_list[pivot_index], num_list[right] = num_list[right], num_list[
pivot_index]
store_index = left
for i in range(left, right):
if num_list[i] < pivot_value:
num_list[store_index], num_list[i] = num_list[i], num_list[store_index]
store_index += 1
num_list[store_index], num_list[right] = num_list[right], num_list[store_index]
return store_index
def quick_sort_1(left: int, right: int, num_list: list[int]) -> list[int]:
if left < right:
m = partition(left, right, num_list)
quick_sort_1(left, m - 1, num_list)
quick_sort_1(m + 1, right, num_list)
return num_list
def quick_sort_2(num_list: list[int]) -> list[int]:
if (list_len := len(num_list)) <= 1:
return num_list
pivot = num_list[random.randint(0, list_len - 1)]
left = list(filter(lambda x: x < pivot, num_list))
center = list(filter(lambda x: x == pivot, num_list))
right = list(filter(lambda x: x > pivot, num_list))
return quick_sort_2(left) + center + quick_sort_2(right)
#教え
Видео 7/22 start -> 30:00
Видео 7/22 start -> 30:00
# Генераторы последовательностей или comprehensions
#пример генератора списка
num_list = [ i for i in range(1,11) if i % 2 == 0]
#способы трансформации ключей списка, через ключи не получится изменить
name_list = {
'Alex': '1',
'Vova': '2',
'Vasya': '3',
'John': '4',
'Igor': '5',
'Nikita': '6',
}
new_list = {}
for name, value in name_list.items():
new_list[f"{name}_{value}"] = value
new_list = {f"{name}_{value}": value
for name, value in name_list.items()}
new_list = dict(map(lambda el: (f"{el[0]}_{el[1]}", el[1]), name_list.items()))
print(new_list)