Форум сайта python.su
Снова здравствуйте господа знающие! В качестве упражнения на тему функций, решил развить идею вот из этой темы: https://python.su/forum/topic/41181/
Задача там была в том, чтобы склепать примитивный тренажёр для первоклассника, с решением арифметических примеров на время..
Вопроса 2:
1) Насколько ̶к̶о̶д̶ ̶г̶о̶в̶н̶о̶ удачная реализация?
2) Можно ли ещё сократить часто повторяющиеся строки кода, особенно в main()?
Собсно код:
from time import time from random import randint def multiply(num_of_exam, corr_answ_count=0): while num_of_exam > 0: x, y = get_operands(mult=True) if get_user_answer(x, y, "*") == str(x * y): print('Верно!') corr_answ_count += 1 else: print(f'Ответ неверный! Правильный ответ:', x * y) num_of_exam -= 1 continue return corr_answ_count def add(num_of_exam, corr_answ_count=0): while num_of_exam > 0: x, y = get_operands() if get_user_answer(x, y, "+") == str(x + y): print('Верно!') corr_answ_count += 1 else: print(f'Ответ неверный! Правильный ответ:', x + y) num_of_exam -= 1 continue return corr_answ_count def subtract(num_of_exam, corr_answ_count=0): while num_of_exam > 0: x, y = get_operands(sub=True) if get_user_answer(x, y, "-") == str(x - y): print('Верно!') corr_answ_count += 1 else: print(f'Ответ неверный! Правильный ответ:', x - y) num_of_exam -= 1 continue return corr_answ_count def divide(num_of_exam, corr_answ_count=0): while num_of_exam > 0: x, y = get_operands(div=True) if get_user_answer(x, y, "/") == str(x // y): print('Верно!') corr_answ_count += 1 else: print(f'Ответ неверный! Правильный ответ:', x // y) num_of_exam -= 1 continue return corr_answ_count def exam_to_solve(): while True: try: examples = int(input('Сколько примеров будем решать? ')) return examples except ValueError: print('Нужно ввести целое число!') continue def get_sign(): vvod = input('С каким знаком будут примеры? +, -, / или *? ') return vvod def get_operands(sub=False, div=False, mult=False): if mult: num_1 = randint(2, 10) num_2 = randint(2, 10) return num_1, num_2 elif div: num_1 = randint(2, 10) num_2 = num_1 * randint(1, 10) return num_2, num_1 elif sub: num_1 = randint(1, 99) num_2 = randint(1, 99) while num_2 >= num_1: num_2 = randint(1, 99) return num_1, num_2 else: num_1 = randint(0, 99) num_2 = randint(0, 99) return num_1, num_2 def get_user_answer(x, y, operator): user_answer = input(f'Сколько будет {x} {operator} {y}?\n') return user_answer def main(amount): oper = get_sign() if oper == '+': print('Время пошло!') start = time() correct_answer = add(amount) print('Затраченное время:', round(time() - start, 2), f'\nПравильных ответов: {correct_answer} из {amount}') elif oper == '-': print('Время пошло!') start = time() correct_answer = subtract(amount) print('Затраченное время:', round(time() - start, 2), f'\nПравильных ответов: {correct_answer} из {amount}') elif oper == '/': print('Время пошло!') start = time() correct_answer = divide(amount) print('Затраченное время:', round(time() - start, 2), f'\nПравильных ответов: {correct_answer} из {amount}') elif oper == '*': print('Время пошло!') start = time() correct_answer = multiply(amount) print('Затраченное время:', round(time() - start, 2), f'\nПравильных ответов: {correct_answer} из {amount}') else: print('Некорректный ввод. Повторите.') return main(amount) print('Завершение программы..') if __name__ == '__main__': print('Калькуляция на время!') count = exam_to_solve() main(count)
Отредактировано Palrom (Май 14, 2022 17:58:44)
Офлайн
[guest@localhost py]$ ./exertime.py
Калькуляция на время!
Сколько примеров будем решать? 0
С каким знаком будут примеры? +, -, / или *? +
Время пошло!
Затраченное время: 0.0
Правильных ответов: 0 из 0
Завершение программы..
[guest@localhost py]$
[guest@localhost py]$ ./exertime.py
Калькуляция на время!
Сколько примеров будем решать? x
Нужно ввести целое число!
Сколько примеров будем решать? -1
С каким знаком будут примеры? +, -, / или *? +
Время пошло!
Затраченное время: 0.0
Правильных ответов: 0 из -1
Завершение программы..
[guest@localhost py]$
[guest@localhost py]$ ./exertime.py
Калькуляция на время!
Сколько примеров будем решать? 1
С каким знаком будут примеры? +, -, / или *? +
Время пошло!
Сколько будет 74 + 74?
Ответ неверный! Правильный ответ: 148
Затраченное время: 7.0
Правильных ответов: 0 из 1
Завершение программы..
[guest@localhost py]$
PalromПервоклассники не проходят умножение и деление, так как у них нет базы ещё для этого. Во втором классе проходят умножение и деление, так как есть база для этого.
Задача там была в том, чтобы склепать примитивный тренажёр для первоклассника
PalromУ тебя не должно быть кода вне функции main(). Поэтому назови свою функцию main() по-другому, типа start_exam() или наподобие, а в функцию main() помести эти три строчки только. Дальше функция main() должна вернуть код 0, который будет возвращён в операционную систему.if __name__ == '__main__': print('Калькуляция на время!') count = exam_to_solve() main(count)
if __name__ == '__main__': sys.exit(main())
PalromПрограмма должна быть 1) правильной 2) понятной 3) легко меняемой.
1) Насколько ̶к̶о̶д̶ ̶г̶о̶в̶н̶о̶ удачная реализация?
Отредактировано py.user.next (Май 14, 2022 05:37:40)
Офлайн
py.user.next
Спасибо за уделённое время и советы!
py.user.nextНу пожалуй дал я маху, да. Школьников в моём окружении нет, спросить некого, а лезть смотреть их программу было лень.
Первоклассники не проходят умножение и деление
py.user.next
не должно быть кода вне функции main()
py.user.nextВсё исправил. Как раз проверка количества примеров-то и была вынесена в отдельную функцию (exam_to_solve) изначально, так что исправилось быстро и легко. По ходу исправления прикрутил перезапуск по желанию
Сейчас надо будеть исправлять процедуру проверки количества примеров, а эта процедура у тебя по всему коду скопирована одна и та же.
py.user.nextА вот тут-то я и встрял. Функцию обозвал prog_body, но как адекватно сделать вызов упомянутых строк, чтоб в глазах не рябило - хз.
функцию под новым именем поменяй так, чтобы выводы строк “время пошло” и “правильных ответов” на экран были только в одном месте этой функции.
py.user.nextЧую, подобное можно исправить функцией-декоратором, к функциям-“считалкам”-то уж точно, но как конкретно воплотить - пока ума не приложу..
бросается в глаза похожий код по всей программе.
import sys from time import time from random import randint def multiply(num_of_exam, corr_answ_count=0): while num_of_exam > 0: x, y = get_operands(mult=True) if get_user_answer(x, y, "*") == str(x * y): print('Верно!') corr_answ_count += 1 else: print(f'Ответ неверный! Правильный ответ:', x * y) num_of_exam -= 1 continue return corr_answ_count def add(num_of_exam, corr_answ_count=0): while num_of_exam > 0: x, y = get_operands() if get_user_answer(x, y, "+") == str(x + y): print('Верно!') corr_answ_count += 1 else: print(f'Ответ неверный! Правильный ответ:', x + y) num_of_exam -= 1 continue return corr_answ_count def subtract(num_of_exam, corr_answ_count=0): while num_of_exam > 0: x, y = get_operands(sub=True) if get_user_answer(x, y, "-") == str(x - y): print('Верно!') corr_answ_count += 1 else: print(f'Ответ неверный! Правильный ответ:', x - y) num_of_exam -= 1 continue return corr_answ_count def divide(num_of_exam, corr_answ_count=0): while num_of_exam > 0: x, y = get_operands(div=True) if get_user_answer(x, y, "/") == str(x // y): print('Верно!') corr_answ_count += 1 else: print(f'Ответ неверный! Правильный ответ:', x // y) num_of_exam -= 1 continue return corr_answ_count def exam_to_solve(): while True: try: examples = int(input('Сколько примеров будем решать? ')) if examples <= 0: print('Нужно решить хотя бы один пример!') return exam_to_solve() else: return examples except ValueError: print('Нужно ввести целое число!') continue def get_sign(): vvod = input('С каким знаком будут примеры? +, -, / или *? ') return vvod def get_operands(sub=False, div=False, mult=False): if mult: num_1 = randint(2, 10) num_2 = randint(2, 10) return num_1, num_2 elif div: num_1 = randint(2, 10) num_2 = num_1 * randint(1, 10) return num_2, num_1 elif sub: num_1 = randint(1, 99) num_2 = randint(1, 99) while num_2 >= num_1: num_2 = randint(1, 99) return num_1, num_2 else: num_1 = randint(0, 99) num_2 = randint(0, 99) return num_1, num_2 def get_user_answer(x, y, operator): user_answer = input(f'Сколько будет {x} {operator} {y}?\n') if user_answer == '': print('Пропустить вопрос нельзя.') return get_user_answer(x, y, operator) return user_answer def prog_body(amount): oper = get_sign() if oper == '+': print('Время пошло!') start = time() correct_answer = add(amount) print('Затраченное время:', round(time() - start, 2), f'\nПравильных ответов: {correct_answer} из {amount}') elif oper == '-': print('Время пошло!') start = time() correct_answer = subtract(amount) print('Затраченное время:', round(time() - start, 2), f'\nПравильных ответов: {correct_answer} из {amount}') elif oper == '/': print('Время пошло!') start = time() correct_answer = divide(amount) print('Затраченное время:', round(time() - start, 2), f'\nПравильных ответов: {correct_answer} из {amount}') elif oper == '*': print('Время пошло!') start = time() correct_answer = multiply(amount) print('Затраченное время:', round(time() - start, 2), f'\nПравильных ответов: {correct_answer} из {amount}') else: print('Некорректный ввод. Повторите.') return prog_body(amount) return None def restart(default=False): user_decision = input('Ещё разок? Y/N ') if user_decision.casefold() == 'y': return True elif user_decision.casefold() == 'n': return default else: print('Не понятно. Повторите ввод.') return restart() def main(): print('Калькуляция на время!') count = exam_to_solve() prog_body(count) if restart(): return main() print('Завершение программы..') return 0 if __name__ == '__main__': sys.exit(main())
Отредактировано Palrom (Май 14, 2022 18:27:14)
Офлайн
PalromОпубликуй код. Очень большие сомнения, что ты всё исправил. Я думаю, там такой же копипаст по всей программе, который и был.
Всё исправил.
PalromИ о чём говорит такое название у функции? Ни о чём. Название функции должно говорить о том, что делает функция. И название должно быть записано в императивной форме (отвечать на вопрос “что сделать?”). Да и выше я тебе название предлагал. Что сделать? “начать экзамен” - start examination - start_exam(). Но не вот это prog_body. Ты не понимаешь, что любая программа автоматически становится частью другой программы, которой ещё нет. Поэтому и функции должны называться так, чтобы это программа могла быть куском какой-то другой программы. А в той другой программе то же самое правило применяется - она является куском какой-то ещё программы. Там тоже функции не называются так, будто она одна единственная.
Функцию обозвал prog_body
>>> def f1(text): ... return '--{}--'.format(text) ... >>> def f2(text): ... return '=={}=='.format(text) ... >>> def print_message(text, func): ... print('Hello, ' + func(text) + '!') ... >>> print_message('Lisa', lambda i: i) Hello, Lisa! >>> print_message('John', f1) Hello, --John--! >>> print_message('Alice', f2) Hello, ==Alice==! >>> print_message('Bob', lambda i: '__' + i + '__') Hello, __Bob__! >>>
Отредактировано py.user.next (Май 14, 2022 14:05:25)
Офлайн
py.user.nextЯ заменил код в первом сообщении.
Опубликуй код
py.user.nextНу так второй мой вопрос из первого поста “сократить часто повторяющиеся строки кода” остаётся открытым. Внятных подсказок на эту тему я не получил.
там такой же копипаст по всей программе
py.user.nextДа ладно, ладно
start examination - start_exam(). Но не вот это prog_body. Ты не понимаешь
py.user.nextЯ всё понимаю, надо стремиться унифицировать, но это же нереально буквально КАЖДУЮ функцию сделать прям ультра-универсальной! Есть какие-то отдельные компоненты, которые, да, можно юзать как подключаемые, но полно и всеми уважаемых библиотек, где есть функции, которые просто бессмысленно импортировать куда-то “в режиме standalone” так сказать. А при внутреннем использовании человек быстро поймёт о чём эта функция.
чтобы это программа могла быть куском какой-то другой программы
py.user.nextНу если потом подключать доп. функционал, вроде взятия остатка и пр., то да, наверное стоит явно обозначить тип операции. Будет сделано.
информация об операции плюс не передаётся, а считается информацией по умолчанию.
Отредактировано Palrom (Май 14, 2022 18:44:07)
Офлайн
PalromНадо добавлять код. Иначе ты портишь топик. Ведь все мои замечания в сообщении касаются первоначального кода, а не того, который написан. Поэтому люди, когда будут читать, будут введены в заблуждение и будут воспринимать материал сумбурно. То есть ты свой топик делаешь бесполезным для форума.
Я заменил код в первом сообщении.
PalromТы рассуждаешь, как новичок, который ничего не видел в жизни. Вот я писал программу последнюю четыре месяца, у меня получилось больше трёх тысяч строк, там функций пару сотен, комментарии к этим функциям я писал неделю, краткие комментарии. Ты думаешь, у кого-то будет время читать какое-то содержимое каких-то функций в нормальной программе, которая хоть что-то делает? Ты глубоко заблуждаешься. Никто даже названия функций читать не будет, потому что это долго, нудно и неинтересно. А если они ещё будут зашифрованы в виде имён в стиле prog_body, по которому не скажешь, что делает функция, твой код тогда вообще выкинут на помойку, потому что никто не будет тратить время на расшифровку твоих функций, о ясности которых ты не позаботился заранее. Ну и, соответственно, если там будет какой-то баг, тебе про него, может быть, напишут, но, скорее всего, нет, потому что слишком долго времени надо тратить на выявление причины, даже если код открыт. Самое прикольное и самое обычный финал всего этого в том, что ты и сам свой собственный код читать не будешь в итоге, потому что когда у тебя будет десяток программ таких, написанных тобой, ты не будешь помнить, где, когда и в какой программе что ты писал, и не будешь помнить, где, когда и в какой программе ты что-то собирался делать. А также ты не будешь помнить, о чём ты там думал, когда ты эту программу писал, потому что к тому времени, как тебе понадобится исправлять в ней какой-то баг, пройдёт уже три года, и за эти три года ты понапишешь кучу других программ и уже давно позабудешь, что ты там когда-то делал. Я вот нахожу многие программы, которые я писал, так я даже не помню, что это я их написал, потому что прошло пять лет, семь лет, где-то и десять лет, всё уже давно поменялось, я уже стал знать в сто раз больше того себя, который был тогда в то время. Я просто открываю код и я не помню, когда я его писал, про что он там и так далее. Мне заново нужно изучать собственный код. И вот благодаря ясности кода я понимаю, что он написан хорошо, потому что на то, чтобы изучить его заново, у меня уходят минуты, а не часы; часы, а не дни; дни, а не недели; недели, а не месяцы.
А при внутреннем использовании человек быстро поймёт о чём эта функция.
PalromКаждый незакрытый вызов функции держит в памяти все её переменные (там не только переменные, там есть и другие ресурсы). Если ты повторишь экзамен тысячу раз, в памяти будет висеть тысяча открытых функций со всеми своими переменными каждая, а потом лимит рекурсии закончится и программа выпадет, потому что больше не может сделать рекурсивный вызов. Это утечка памяти. Так что замени все такие вызовы на циклы.if restart(): return main()
[guest@localhost exertime]$ yes 1000 | ./exertime2.py >/dev/null
Fatal Python error: Cannot recover from stack overflow.
Current thread 0x00007f7a6d879700 (most recent call first):
File "./exertime2.py", line 69 in get_sign
File "./exertime2.py", line 104 in start_exam
...
File "./exertime2.py", line 131 in start_exam
...
Aborted (стек памяти сброшен на диск)
[guest@localhost exertime]$
PalromПисать без копипаста, который у тебя по всему коду и здесь и там, реально. Просто у тебя не хватает опыта в предварительном мышлении, в предварительном продумывании программы, поэтому ты сначала пишешь код, а потом думаешь, как его писать вообще. Оттуда же проистекают твои эти названия функций, которые ни к селу ни к городу. Сначала надо придумать вызов функции, сначала придумаывается имя вызываемой функции, а уже после этого придумывается её содержимое. А у тебя же наоборот всё. Сначала ты придумываешь содержимое функции, а потом придумываешь название для неё. Вот оттуда и получается, что у тебя функции не согласованы друг с другом, код неясный и разорванный, а не целостный, и постепенно превращается в спагетти, в котором уже ничего не разберёшь. Со временем он закупорит сам себя и ты его не сможешь продолжать разрабатывать дальше. Придётся его выкинуть или оставить в устаревшем виде навсегда. Если ты его писал день, это не жалко. Другое дело, если ты писал его год.
но это же нереально буквально КАЖДУЮ функцию сделать прям ультра-универсальной!
Отредактировано py.user.next (Май 14, 2022 16:26:52)
Офлайн
py.user.nextСтарый код вернул в топ. Код с последними исправлениями (рекурсивные вызовы пока не заменены на циклы):
Надо добавлять код.
import sys from time import time from random import randint def multiply(num_of_exam, corr_answ_count=0): while num_of_exam > 0: x, y = get_operands(mult=True) if get_user_answer(x, y, "*") == str(x * y): print('Верно!') corr_answ_count += 1 else: print(f'Ответ неверный! Правильный ответ:', x * y) num_of_exam -= 1 continue return corr_answ_count def add(num_of_exam, corr_answ_count=0): while num_of_exam > 0: x, y = get_operands(add=True) if get_user_answer(x, y, "+") == str(x + y): print('Верно!') corr_answ_count += 1 else: print(f'Ответ неверный! Правильный ответ:', x + y) num_of_exam -= 1 continue return corr_answ_count def subtract(num_of_exam, corr_answ_count=0): while num_of_exam > 0: x, y = get_operands(sub=True) if get_user_answer(x, y, "-") == str(x - y): print('Верно!') corr_answ_count += 1 else: print(f'Ответ неверный! Правильный ответ:', x - y) num_of_exam -= 1 continue return corr_answ_count def divide(num_of_exam, corr_answ_count=0): while num_of_exam > 0: x, y = get_operands(div=True) if get_user_answer(x, y, "/") == str(x // y): print('Верно!') corr_answ_count += 1 else: print(f'Ответ неверный! Правильный ответ:', x // y) num_of_exam -= 1 continue return corr_answ_count def exam_to_solve(): while True: try: examples = int(input('Сколько примеров будем решать? ')) if examples <= 0: print('Нужно решить хотя бы один пример!') return exam_to_solve() else: return examples except ValueError: print('Нужно ввести целое число!') continue def get_sign(): vvod = input('С каким знаком будут примеры? +, -, / или *? ') return vvod def get_operands(add=False, sub=False, div=False, mult=False): if mult: num_1 = randint(2, 10) num_2 = randint(2, 10) return num_1, num_2 elif div: num_1 = randint(2, 10) num_2 = num_1 * randint(1, 10) return num_2, num_1 elif sub: num_1 = randint(1, 99) num_2 = randint(1, 99) while num_2 >= num_1: num_2 = randint(1, 99) return num_1, num_2 elif add: num_1 = randint(0, 99) num_2 = randint(0, 99) return num_1, num_2 else: num_1 = randint(0, 99) num_2 = randint(0, 99) return num_1, num_2 def get_user_answer(x, y, operator): user_answer = input(f'Сколько будет {x} {operator} {y}?\n') if user_answer == '': print('Пропустить вопрос нельзя.') return get_user_answer(x, y, operator) return user_answer def start_exam(amount): oper = get_sign() if oper == '+': print('Время пошло!') start = time() correct_answer = add(amount) print('Затраченное время:', round(time() - start, 2), f'\nПравильных ответов: {correct_answer} из {amount}') elif oper == '-': print('Время пошло!') start = time() correct_answer = subtract(amount) print('Затраченное время:', round(time() - start, 2), f'\nПравильных ответов: {correct_answer} из {amount}') elif oper == '/': print('Время пошло!') start = time() correct_answer = divide(amount) print('Затраченное время:', round(time() - start, 2), f'\nПравильных ответов: {correct_answer} из {amount}') elif oper == '*': print('Время пошло!') start = time() correct_answer = multiply(amount) print('Затраченное время:', round(time() - start, 2), f'\nПравильных ответов: {correct_answer} из {amount}') else: print('Некорректный ввод. Повторите.') return start_exam(amount) return None def restart(default=False): user_decision = input('Ещё разок? Y/N ') if user_decision.casefold() == 'y': return True elif user_decision.casefold() == 'n': return default else: print('Не понятно. Повторите ввод.') return restart() def main(): print('Калькуляция на время!') count = exam_to_solve() start_exam(count) if restart(): return main() print('Завершение программы..') return 0 if __name__ == '__main__': sys.exit(main())
Отредактировано Palrom (Май 14, 2022 18:41:58)
Офлайн
py.user.nextДа, на колхоз похоже. Я иногда намерено упрощаю вещи и отбрасываю лишние вопросы, ибо итак тяжело это всё, и чем дальше тем тяжелее, защитная реакция психики наверное, чтоб не сломаться и не бросить этим заниматься. Если я раньше не кодил, то это не значит что я ни дня не работал и не решал сложные задачи. Я понял о чём речь, знаю, что зря упрощаю те самые вещи и вопросы те совсем не лишние в итоге (в таком ремесле как программирование, я так понял всё лишнее и без меня уже поотсекали). И тоже натыкался на свою старую работу иногда и задавался вопросом “кто это придумал бл@!”.
Ты рассуждаешь, как новичок
py.user.nextНу пока это действительно так. И имена функциям придумываю позже, да. Пока руководствуюсь лозунгом “главное начать” а там как кривая выведет. UPD. На самом деле я уже догадываюсь, как избавиться от копипасты, но для этого надо почти всю структуру программы переделать..
ты сначала пишешь код, а потом думаешь, как его писать вообще.
py.user.nextА что это за чудо-юдо отладочные команды такие кстати? Это внешние какие-то модули или встроенные инструменты питона? Где почитать?
пример выпадения твоей программы, когда ей подаёшь строку 1000 всё время
Отредактировано Palrom (Май 14, 2022 18:58:11)
Офлайн
PalromЭто Linux. Её надо поставить второй системой (чтобы винды в памяти не было, как при установке в виртуалку) и там заниматься программированием. Там есть много программ всяких, которых в винде нет. Программа yes посылает бесконечно строку y или заданную строку на вход другой программы. Она сделана специально, чтобы глушить программы, которые постоянно останавливают своё выполнение и у пользователя спрашивают yes/no и ждут ответ y? Чтобы отвечать y всё время и выполнение программы не останавливалось, сделана эта программа когда-то давно. В винде таких программ нет. Там есть только всякая бесполезная хрень.
А что это за чудо-юдо отладочные команды такие кстати?
PalromТы говоришь, что якобы будешь читать функции. Значит, ты не видел никогда программ, которые физически прочитать невозможно, потому что только читать ты их будешь несколько месяцев. Просто увеличь количество строк кода до тысячи, до пяти тысяч и ты не прочитаешь из них потом больше ста строк. Чтобы не перечитывать код, существуют юнит-тесты. Когда баг исправляется, не нужно перечитывать код, чтобы убедиться, что исправление бага не сломало ничего нового в коде; просто надо запустить юнит-тесты, которые пройдут по коду и заглянут в каждый его угол. А без юнит-тестов ты будешь десять раз исправлять баги и десять раз перечитывать весь код, чтобы гарантировать, что он правильно работает, что твоё исправление ни на что не повлияло.
Если я раньше не кодил, то это не значит что я ни дня не работал и не решал сложные задачи.
Отредактировано py.user.next (Май 14, 2022 19:09:47)
Офлайн
py.user.next
Убунту подойдёт последняя? Гугл говорит, что это лучшее решение как для новичков так и для профи.
py.user.nextЭто для меня пока, даже не тёмный лес а бетонная стена. Дайте время в линукс вползти хотя бы..
Чтобы не перечитывать код, существуют юнит-тесты
py.user.nextНу таких больших, да, не видел. Кстати, может знаете где можно поглазеть на образцовый код? чтоб прям из палаты мер и весов, желательно по возрастанию сложности и не старый, без древнего формата, вроде ‘Hello, %s’ % name. UPD. Хотя вопрос наверное глуповат, достаточно открыть и почитать любую встроенную библиотеку..
ты не видел никогда программ, которые физически прочитать невозможно, потому что только читать ты их будешь несколько месяцев
Отредактировано Palrom (Май 15, 2022 11:59:40)
Офлайн