Repository: andreypomortsev/yndx-python-handbook

Issue:
Feature: Add 5 solutions for 4.2 A-E
1. Выложить решения для задач A,B,C,D,E параграфа 4.2
2. Покрыть тестами 100% решений, обновить README.md.

Hints from issue comments:

Solution patch:
diff --git a/README.md b/README.md
index 18017cdc..d82c94ff 100644
--- a/README.md
+++ b/README.md
@@ -503,6 +503,28 @@ def main():
 
 </details>
 
+<details>
+<summary><h3>4.2 Позиционные и именованные аргументы. Функции высших порядков. Лямбда-функции</h3></summary>
+
+- [4.2 Позиционные и именованные аргументы. Функции высших порядков. Лямбда-функции](https://education.yandex.ru/handbook/python/article/pozicionnye-i-imenovannye-argumenty-funkcii-vysshih-poryadkov-lyambda-funkcii)
+
+### [Тестовые данные для задач](./tests/data/test_data_42.py)
+
+| Решение              | Тесты                |
+|----------------------|----------------------|
+| А. [Генератор списков](./solutions/4.2/42_a.py) | [✅](./tests/4.2/test_42_a.py) |
+| B. [Генератор матриц](./solutions/4.2/42_b.py) | [✅](./tests/4.2/test_42_b.py) |
+| C. [Функциональный нод 2.0](./solutions/4.2/42_c.py) | [✅](./tests/4.2/test_42_c.py) |
+| D. [Имя of the month 2.0](./solutions/4.2/42_d.py) | [✅](./tests/4.2/test_42_d.py) |
+| E. [Подготовка данных](./solutions/4.2/42_e.py) | [✅](./tests/4.2/test_42_e.py) |
+| F. [Кофейня](./solutions/4.2/42_f.py) | [❌](./tests/4.2/test_42_f.py) |
+| G. [В эфире рубрика «Эксперименты»](./solutions/4.2/42_g.py) | [❌](./tests/4.2/test_42_g.py) |
+| H. [Длинная сортировка](./solutions/4.2/42_h.py) | [❌](./tests/4.2/test_42_h.py) |
+| I. [Чётная фильтрация](./solutions/4.2/42_i.py) | [❌](./tests/4.2/test_42_i.py) |
+| J. [Ключевой секрет](./solutions/4.2/42_j.py) | [❌](./tests/4.2/test_42_j.py) |
+
+</details>
+
 ## Создание Issue
 
 Если вы обнаружили ошибку, очепятку или баг в проекте, пожалуйста, создайте новый issue, следуя этому шаблону:
diff --git a/solutions/3.5/35_t.py b/solutions/3.5/35_t.py
index 339909c3..2efb1adb 100644
--- a/solutions/3.5/35_t.py
+++ b/solutions/3.5/35_t.py
@@ -4,7 +4,9 @@
 with open("numbers.num", "rb") as file:
     while chunk := file.read(CHUNK_SIZE):
         for i in range(0, len(chunk) - 1, 2):
-            two_bytes = chunk[i: i + 2]  # noqa E201
+            # fmt: off
+            two_bytes = chunk[i: i + 2]
+            # fmt: on
             sum_of_numbers += int.from_bytes(two_bytes, byteorder="big")
 
 print(sum_of_numbers & 0xFFFF)
diff --git a/solutions/4.2/42_a.py b/solutions/4.2/42_a.py
new file mode 100644
index 00000000..d0aeca07
--- /dev/null
+++ b/solutions/4.2/42_a.py
@@ -0,0 +1,5 @@
+from typing import List
+
+
+def make_list(length: int, value: int = 0) -> List[int]:
+    return [value] * length
diff --git a/solutions/4.2/42_b.py b/solutions/4.2/42_b.py
new file mode 100644
index 00000000..7f2a463d
--- /dev/null
+++ b/solutions/4.2/42_b.py
@@ -0,0 +1,12 @@
+from typing import List, Tuple, Union
+
+
+def make_matrix(
+    size: Union[Tuple[int], int], value: Union[int, None] = None
+) -> List[List[int]]:
+    if not value:
+        value = 0
+    if isinstance(size, int):
+        size = (size, size)
+
+    return [[value] * size[0] for _ in range(size[1])]
diff --git a/solutions/4.2/42_c.py b/solutions/4.2/42_c.py
new file mode 100644
index 00000000..d284dad6
--- /dev/null
+++ b/solutions/4.2/42_c.py
@@ -0,0 +1,11 @@
+def gcd(*numbers) -> int:
+    if len(numbers) < 2:
+        return numbers[0] if numbers else None
+
+    a = numbers[0]
+
+    for b in numbers[1:]:
+        while b:
+            a, b = b, a % b
+
+    return a
diff --git a/solutions/4.2/42_d.py b/solutions/4.2/42_d.py
new file mode 100644
index 00000000..33511595
--- /dev/null
+++ b/solutions/4.2/42_d.py
@@ -0,0 +1,19 @@
+from typing import Union
+
+
+def month(number: Union[int, str], lang: str = "ru") -> str:
+    months = {
+        "1": {"en": "January", "ru": "Январь"},
+        "2": {"en": "February", "ru": "Февраль"},
+        "3": {"en": "March", "ru": "Март"},
+        "4": {"en": "April", "ru": "Апрель"},
+        "5": {"en": "May", "ru": "Май"},
+        "6": {"en": "June", "ru": "Июнь"},
+        "7": {"en": "July", "ru": "Июль"},
+        "8": {"en": "August", "ru": "Август"},
+        "9": {"en": "September", "ru": "Сентябрь"},
+        "10": {"en": "October", "ru": "Октябрь"},
+        "11": {"en": "November", "ru": "Ноябрь"},
+        "12": {"en": "December", "ru": "Декабрь"},
+    }
+    return months.get(str(number), {}).get(lang, "")
diff --git a/solutions/4.2/42_e.py b/solutions/4.2/42_e.py
new file mode 100644
index 00000000..2ba58079
--- /dev/null
+++ b/solutions/4.2/42_e.py
@@ -0,0 +1,14 @@
+def to_string(*data, sep: str = " ", end: str = "\n") -> str:
+    n = len(data)
+    result = []
+
+    for i in range(n):
+        element = str(data[i])
+
+        if i == n - 1:
+            sep = end
+
+        result.append(element)
+        result.append(sep)
+
+    return "".join(result)


Test patch:
diff --git a/tests/4.1/test_41_a.py b/tests/4.1/test_41_a.py
index 58766a6d..766a62e6 100644
--- a/tests/4.1/test_41_a.py
+++ b/tests/4.1/test_41_a.py
@@ -11,7 +11,7 @@
     a_test_data,
     ids=[i[-1] for i in a_test_data],
 )
-def test_input_output(
+def test_print_hello(
     monkeypatch: pytest.MonkeyPatch,
     decorated_function: Callable,
     arg: str,
diff --git a/tests/4.1/test_41_b.py b/tests/4.1/test_41_b.py
index c29f7682..6a0c5a2a 100644
--- a/tests/4.1/test_41_b.py
+++ b/tests/4.1/test_41_b.py
@@ -10,7 +10,7 @@
     b_test_data,
     ids=[i[-1] for i in b_test_data],
 )
-def test_input_output(
+def test_gcd(
     decorated_function: Callable,
     args: Tuple[int],
     expected_output: str,
diff --git a/tests/4.1/test_41_c.py b/tests/4.1/test_41_c.py
index f7f53a4a..075479f6 100644
--- a/tests/4.1/test_41_c.py
+++ b/tests/4.1/test_41_c.py
@@ -10,7 +10,7 @@
     c_test_data,
     ids=[i[-1] for i in c_test_data],
 )
-def test_input_output(
+def test_number_length(
     decorated_function: Callable,
     arg: int,
     expected_output: int,
diff --git a/tests/4.1/test_41_d.py b/tests/4.1/test_41_d.py
index 82c6ad2b..cd20800b 100644
--- a/tests/4.1/test_41_d.py
+++ b/tests/4.1/test_41_d.py
@@ -10,7 +10,7 @@
     d_test_data,
     ids=[i[-1] for i in d_test_data],
 )
-def test_input_output(
+def test_month(
     decorated_function: Callable,
     args: Tuple[Union[int, str], str],
     expected_output: str,
diff --git a/tests/4.1/test_41_e.py b/tests/4.1/test_41_e.py
index 0c7016a5..d51767d1 100644
--- a/tests/4.1/test_41_e.py
+++ b/tests/4.1/test_41_e.py
@@ -10,7 +10,7 @@
     e_test_data,
     ids=[i[-1] for i in e_test_data],
 )
-def test_input_output(
+def test_split_numbers(
     decorated_function: Callable,
     arg: str,
     expected_output: Tuple[int],
diff --git a/tests/4.1/test_41_f.py b/tests/4.1/test_41_f.py
index 0147da94..f02d25db 100644
--- a/tests/4.1/test_41_f.py
+++ b/tests/4.1/test_41_f.py
@@ -11,7 +11,7 @@
     f_test_data,
     ids=[i[-1] for i in f_test_data],
 )
-def test_input_output(
+def test_modern_print(
     monkeypatch: pytest.MonkeyPatch,
     decorated_function: Callable,
     args: Tuple[str],
diff --git a/tests/4.1/test_41_g.py b/tests/4.1/test_41_g.py
index 55db45bd..ef44e7d1 100644
--- a/tests/4.1/test_41_g.py
+++ b/tests/4.1/test_41_g.py
@@ -10,7 +10,7 @@
     g_test_data,
     ids=[i[-1] for i in g_test_data],
 )
-def test_input_output(
+def test_can_eat(
     decorated_function: Callable,
     args: Tuple[Tuple[int]],
     expected_output: bool,
diff --git a/tests/4.1/test_41_h.py b/tests/4.1/test_41_h.py
index 9e9cccbf..f7e9d6b2 100644
--- a/tests/4.1/test_41_h.py
+++ b/tests/4.1/test_41_h.py
@@ -10,7 +10,7 @@
     h_test_data,
     ids=[i[-1] for i in h_test_data],
 )
-def test_input_output(
+def test_is_palindrome(
     decorated_function: Callable,
     args: Any,
     expected_output: bool,
diff --git a/tests/4.1/test_41_i.py b/tests/4.1/test_41_i.py
index 01849729..539daf16 100644
--- a/tests/4.1/test_41_i.py
+++ b/tests/4.1/test_41_i.py
@@ -11,7 +11,7 @@
     i_test_data,
     ids=[i[-1] for i in i_test_data],
 )
-def test_input_output(
+def test_is_prime(
     decorated_function: Callable,
     arg: int,
     expected_output: int,
@@ -24,7 +24,7 @@ def test_input_output(
 
 @pytest.mark.slow
 @pytest.mark.xfail(reason="Слишком большие числа на входе.")
-def test_time_overload(
+def test_is_prime_time_overload(
     decorated_function: Callable,
 ):
     """
diff --git a/tests/4.1/test_41_j.py b/tests/4.1/test_41_j.py
index a0da5be0..d7056e99 100644
--- a/tests/4.1/test_41_j.py
+++ b/tests/4.1/test_41_j.py
@@ -10,7 +10,7 @@
     j_test_data,
     ids=[i[-1] for i in j_test_data],
 )
-def test_input_output(
+def test_merge(
     decorated_function: Callable,
     args: Tuple[Tuple[int]],
     expected_output: Tuple[int],
diff --git a/tests/4.2/test_42_a.py b/tests/4.2/test_42_a.py
new file mode 100644
index 00000000..1f71f251
--- /dev/null
+++ b/tests/4.2/test_42_a.py
@@ -0,0 +1,21 @@
+from typing import Callable, List, Tuple
+
+import pytest
+
+from tests.data.test_data_42 import a_test_data
+
+
+@pytest.mark.parametrize(
+    "args, expected_output, _",
+    a_test_data,
+    ids=[i[-1] for i in a_test_data],
+)
+def test_make_list(
+    decorated_function: Callable,
+    args: Tuple[Tuple[int]],
+    expected_output: List[int],
+    _: str,
+) -> None:
+    returned_output = decorated_function(*args)
+
+    assert returned_output == expected_output
diff --git a/tests/4.2/test_42_b.py b/tests/4.2/test_42_b.py
new file mode 100644
index 00000000..0d29bcc9
--- /dev/null
+++ b/tests/4.2/test_42_b.py
@@ -0,0 +1,28 @@
+from typing import Callable, Tuple, Union
+
+import pytest
+
+from tests.data.test_data_42 import b_test_data
+
+
+@pytest.mark.parametrize(
+    "args, expected_output, _",
+    b_test_data,
+    ids=[i[-1] for i in b_test_data],
+)
+def test_make_matrix(
+    decorated_function: Callable,
+    args: Tuple[Union[Tuple[int], int]],
+    expected_output: Tuple[int],
+    _: str,
+) -> None:
+    returned_output = decorated_function(*args)
+
+    assert returned_output == expected_output
+
+    returned_output[0][0] = "c"
+    expected_output[0][0] = "c"
+
+    error_msg = "Все строки матрицы являются одним и тем же списком."
+
+    assert returned_output == expected_output, error_msg
diff --git a/tests/4.2/test_42_c.py b/tests/4.2/test_42_c.py
new file mode 100644
index 00000000..670d2e4f
--- /dev/null
+++ b/tests/4.2/test_42_c.py
@@ -0,0 +1,21 @@
+from typing import Callable, Tuple
+
+import pytest
+
+from tests.data.test_data_42 import c_test_data
+
+
+@pytest.mark.parametrize(
+    "args, expected_output, _",
+    c_test_data,
+    ids=[i[-1] for i in c_test_data],
+)
+def test_gcd(
+    decorated_function: Callable,
+    args: Tuple[Tuple[int]],
+    expected_output: Tuple[int],
+    _: str,
+) -> None:
+    returned_output = decorated_function(*args)
+
+    assert returned_output == expected_output
diff --git a/tests/4.2/test_42_d.py b/tests/4.2/test_42_d.py
new file mode 100644
index 00000000..78ff0b2b
--- /dev/null
+++ b/tests/4.2/test_42_d.py
@@ -0,0 +1,21 @@
+from typing import Callable, Tuple
+
+import pytest
+
+from tests.data.test_data_42 import d_test_data
+
+
+@pytest.mark.parametrize(
+    "args, expected_output, _",
+    d_test_data,
+    ids=[i[-1] for i in d_test_data],
+)
+def test_month(
+    decorated_function: Callable,
+    args: Tuple[Tuple[int]],
+    expected_output: Tuple[int],
+    _: str,
+) -> None:
+    returned_output = decorated_function(*args)
+
+    assert returned_output == expected_output
diff --git a/tests/4.2/test_42_e.py b/tests/4.2/test_42_e.py
new file mode 100644
index 00000000..0a84ba9b
--- /dev/null
+++ b/tests/4.2/test_42_e.py
@@ -0,0 +1,22 @@
+from typing import Callable, Dict, Tuple
+
+import pytest
+
+from tests.data.test_data_42 import e_test_data
+
+
+@pytest.mark.parametrize(
+    "args, kwargs, expected_output, _",
+    e_test_data,
+    ids=[i[-1] for i in e_test_data],
+)
+def test_to_string(
+    decorated_function: Callable,
+    args: Tuple[Tuple[int]],
+    kwargs: Dict[str, str],
+    expected_output: Tuple[int],
+    _: str,
+) -> None:
+    returned_output = decorated_function(*args, **kwargs)
+
+    assert returned_output == expected_output
diff --git a/tests/constants.py b/tests/constants.py
index b2e04dd1..76eb7dc6 100644
--- a/tests/constants.py
+++ b/tests/constants.py
@@ -23,5 +23,12 @@
         "h": "is_palindrome",
         "i": "is_prime",
         "j": "merge",
-    }
+    },
+    "4.2": {
+        "a": "make_list",
+        "b": "make_matrix",
+        "c": "gcd",
+        "d": "month",
+        "e": "to_string",
+    },
 }
diff --git a/tests/data/test_data_42.py b/tests/data/test_data_42.py
new file mode 100644
index 00000000..d4b869a8
--- /dev/null
+++ b/tests/data/test_data_42.py
@@ -0,0 +1,84 @@
+from tests.data.test_data_41 import d_test_data as d_test_data_41
+
+a_test_data = [
+    ((3,), [0, 0, 0], "first open test"),
+    ((5, 1), [1, 1, 1, 1, 1], "second open test"),
+    ((1, 5), [5], "single value"),
+    ((5, 5), [5, 5, 5, 5, 5], "double value"),
+    ((1,), [0], "one default value"),
+    ((1, 290293843), [290293843], "one and big value"),
+]
+
+b_test_data = [
+    ((3,), [[0, 0, 0], [0, 0, 0], [0, 0, 0]], "first open test"),
+    (((4, 2), 1), [[1, 1, 1, 1], [1, 1, 1, 1]], "second open test"),
+    (
+        (5, 1),
+        [
+            [1, 1, 1, 1, 1],
+            [1, 1, 1, 1, 1],
+            [1, 1, 1, 1, 1],
+            [1, 1, 1, 1, 1],
+            [1, 1, 1, 1, 1],
+        ],
+        "five ones",
+    ),
+    (((3, 1), 9), [[9, 9, 9]], "one row matrix"),
+    (((1, 3), 9), [[9], [9], [9]], "one column matrix"),
+    (((1, 1), 9), [[9]], "one value nine"),
+    (((1, 1),), [[0]], "one value default"),
+    (((1, 1), 0), [[0]], "zero value"),
+    (((1, 1), 1), [[1]], "one value one"),
+    (((1, 1), 290293843), [[290293843]], "one and big value"),
+]
+
+c_test_data = [
+    ((3,), 3, "first open test"),
+    ((36, 48, 156, 100500), 12, "second open test"),
+    ((3, 5, 7, 9, 17, 33), 1, "gcd of small primes"),
+    ((2, 290293843, 290293847, 290293849), 1, "gcd of big primes"),
+    ((290293843,), 290293843, "one big prime"),
+    ((2,) * 10**5, 2, "a lot equal of numbers"),
+    (tuple(range(198)), 1, "a lot of increasing numbers"),
+    (tuple(range(0, 1298, 2)), 2, "a lot of even increasing numbers"),
+    (tuple(range(1, 9297, 3)), 1, "a lot of odd increasing numbers"),
+]
+
+d_test_data = [
+    ((1, "en"), "January", "first open test"),
+    ((7,), "Июль", "second open test"),
+    ((1,), "Январь", "Jan"),
+    ((2,), "Февраль", "Feb"),
+    ((3,), "Март", "Mar"),
+    ((4,), "Апрель", "Apr"),
+    ((5,), "Май", "May"),
+    ((6,), "Июнь", "Jun"),
+    ((8,), "Август", "Jul"),
+    ((9,), "Сентябрь", "Sep"),
+    ((10,), "Октябрь", "Oct"),
+    ((11,), "Ноябрь", "Nov"),
+    ((12,), "Декабрь", "Dec"),
+] + d_test_data_41[2:]
+
+e_test_data = [
+    ((1, 2, 3), {}, "1 2 3\n", "first open test"),
+    (
+        [7, 3, 1, "hello", (1, 2, 3)],
+        {"sep": ", ", "end": "!"},
+        "7, 3, 1, hello, (1, 2, 3)!",
+        "second open test",
+    ),
+    (("lambda x: x",), {"sep": " ", "end": "!"}, "lambda x: x!", "lambda"),
+    (
+        (1, 2, 3),
+        {"sep": "\nlambda x: x\n", "end": "\n!!!"},
+        "1\nlambda x: x\n2\nlambda x: x\n3\n!!!",
+        "integers with crazy sep",
+    ),
+    (
+        ("lambda x: x", [9, 8, 7, 6], {"one": 1, "two": 3}),
+        {},
+        "lambda x: x [9, 8, 7, 6] {'one': 1, 'two': 3}\n",
+        "mix of data types",
+    ),
+]