Уведомления

Группа в Telegram: @pythonsu

#1 Май 13, 2022 18:29:04

Palrom
Зарегистрирован: 2022-04-21
Сообщения: 82
Репутация: +  5  -
Профиль   Отправить e-mail  

Избежать частых повторений одного и того же кода

Снова здравствуйте господа знающие! В качестве упражнения на тему функций, решил развить идею вот из этой темы: 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)

Офлайн

#2 Май 13, 2022 23:31:02

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9873
Репутация: +  853  -
Профиль   Отправить e-mail  

Избежать частых повторений одного и того же кода

[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
  
if __name__ == '__main__':
    print('Калькуляция на время!')
    count = exam_to_solve()
    main(count)
У тебя не должно быть кода вне функции main(). Поэтому назови свою функцию main() по-другому, типа start_exam() или наподобие, а в функцию main() помести эти три строчки только. Дальше функция main() должна вернуть код 0, который будет возвращён в операционную систему.
  
if __name__ == '__main__':
    sys.exit(main())

Palrom
1) Насколько ̶к̶о̶д̶ ̶г̶о̶в̶н̶о̶ удачная реализация?
Программа должна быть 1) правильной 2) понятной 3) легко меняемой.
Вот при исправлении ошибок ты и узнаешь, насколько хороша твоя реализация.

Если ты её начнёшь менять, окажется, что она разрастается очень не удобно, а после того, как она разрастётся из-за обычных исправлений ошибок, она станет очень запутанной и непонятной, а это приведёт к тому, что она станет неправильно работать в конечном счёте и это будет сложно определить.

В первую очередь бросается в глаза похожий код по всей программе. Сейчас надо будеть исправлять процедуру проверки количества примеров, а эта процедура у тебя по всему коду скопирована одна и та же. В итоге тебе придётся по всему коду эту процедуру менять одним и тем же образом. Эта процедура должна находиться в одной функции, которую один раз поменял и все эти проверки количества примеров поменялись одним махом.

Функцию main() переименуй, как я сказал выше, а затем эту функцию под новым именем поменяй так, чтобы выводы строк “время пошло” и “правильных ответов” на экран были только в одном месте этой функции.



Отредактировано py.user.next (Май 14, 2022 05:37:40)

Офлайн

#3 Май 14, 2022 12:52:12

Palrom
Зарегистрирован: 2022-04-21
Сообщения: 82
Репутация: +  5  -
Профиль   Отправить e-mail  

Избежать частых повторений одного и того же кода

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)

Офлайн

#4 Май 14, 2022 13:43:31

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9873
Репутация: +  853  -
Профиль   Отправить e-mail  

Избежать частых повторений одного и того же кода

Palrom
Всё исправил.
Опубликуй код. Очень большие сомнения, что ты всё исправил. Я думаю, там такой же копипаст по всей программе, который и был.

Palrom
Функцию обозвал prog_body
И о чём говорит такое название у функции? Ни о чём. Название функции должно говорить о том, что делает функция. И название должно быть записано в императивной форме (отвечать на вопрос “что сделать?”). Да и выше я тебе название предлагал. Что сделать? “начать экзамен” - start examination - start_exam(). Но не вот это 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)

Офлайн

#5 Май 14, 2022 15:03:43

Palrom
Зарегистрирован: 2022-04-21
Сообщения: 82
Репутация: +  5  -
Профиль   Отправить e-mail  

Избежать частых повторений одного и того же кода

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)

Офлайн

#6 Май 14, 2022 16:20:31

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9873
Репутация: +  853  -
Профиль   Отправить e-mail  

Избежать частых повторений одного и того же кода

Palrom
Я заменил код в первом сообщении.
Надо добавлять код. Иначе ты портишь топик. Ведь все мои замечания в сообщении касаются первоначального кода, а не того, который написан. Поэтому люди, когда будут читать, будут введены в заблуждение и будут воспринимать материал сумбурно. То есть ты свой топик делаешь бесполезным для форума.

Palrom
А при внутреннем использовании человек быстро поймёт о чём эта функция.
Ты рассуждаешь, как новичок, который ничего не видел в жизни. Вот я писал программу последнюю четыре месяца, у меня получилось больше трёх тысяч строк, там функций пару сотен, комментарии к этим функциям я писал неделю, краткие комментарии. Ты думаешь, у кого-то будет время читать какое-то содержимое каких-то функций в нормальной программе, которая хоть что-то делает? Ты глубоко заблуждаешься. Никто даже названия функций читать не будет, потому что это долго, нудно и неинтересно. А если они ещё будут зашифрованы в виде имён в стиле prog_body, по которому не скажешь, что делает функция, твой код тогда вообще выкинут на помойку, потому что никто не будет тратить время на расшифровку твоих функций, о ясности которых ты не позаботился заранее. Ну и, соответственно, если там будет какой-то баг, тебе про него, может быть, напишут, но, скорее всего, нет, потому что слишком долго времени надо тратить на выявление причины, даже если код открыт. Самое прикольное и самое обычный финал всего этого в том, что ты и сам свой собственный код читать не будешь в итоге, потому что когда у тебя будет десяток программ таких, написанных тобой, ты не будешь помнить, где, когда и в какой программе что ты писал, и не будешь помнить, где, когда и в какой программе ты что-то собирался делать. А также ты не будешь помнить, о чём ты там думал, когда ты эту программу писал, потому что к тому времени, как тебе понадобится исправлять в ней какой-то баг, пройдёт уже три года, и за эти три года ты понапишешь кучу других программ и уже давно позабудешь, что ты там когда-то делал. Я вот нахожу многие программы, которые я писал, так я даже не помню, что это я их написал, потому что прошло пять лет, семь лет, где-то и десять лет, всё уже давно поменялось, я уже стал знать в сто раз больше того себя, который был тогда в то время. Я просто открываю код и я не помню, когда я его писал, про что он там и так далее. Мне заново нужно изучать собственный код. И вот благодаря ясности кода я понимаю, что он написан хорошо, потому что на то, чтобы изучить его заново, у меня уходят минуты, а не часы; часы, а не дни; дни, а не недели; недели, а не месяцы.

Palrom
  
    if restart():
        return main()
Каждый незакрытый вызов функции держит в памяти все её переменные (там не только переменные, там есть и другие ресурсы). Если ты повторишь экзамен тысячу раз, в памяти будет висеть тысяча открытых функций со всеми своими переменными каждая, а потом лимит рекурсии закончится и программа выпадет, потому что больше не может сделать рекурсивный вызов. Это утечка памяти. Так что замени все такие вызовы на циклы.

Вот пример выпадения твоей программы, когда ей подаёшь строку 1000 всё время. Она пытается решить тысячу примеров и ближе к тысячному примеру выпадает, потому что в питоне по умолчанию стоит запрет на бесконечную рекурсию.
[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)

Офлайн

#7 Май 14, 2022 17:55:58

Palrom
Зарегистрирован: 2022-04-21
Сообщения: 82
Репутация: +  5  -
Профиль   Отправить e-mail  

Избежать частых повторений одного и того же кода

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)

Офлайн

#8 Май 14, 2022 18:21:10

Palrom
Зарегистрирован: 2022-04-21
Сообщения: 82
Репутация: +  5  -
Профиль   Отправить e-mail  

Избежать частых повторений одного и того же кода

py.user.next
Ты рассуждаешь, как новичок
Да, на колхоз похоже. Я иногда намерено упрощаю вещи и отбрасываю лишние вопросы, ибо итак тяжело это всё, и чем дальше тем тяжелее, защитная реакция психики наверное, чтоб не сломаться и не бросить этим заниматься. Если я раньше не кодил, то это не значит что я ни дня не работал и не решал сложные задачи. Я понял о чём речь, знаю, что зря упрощаю те самые вещи и вопросы те совсем не лишние в итоге (в таком ремесле как программирование, я так понял всё лишнее и без меня уже поотсекали). И тоже натыкался на свою старую работу иногда и задавался вопросом “кто это придумал бл@!”.
py.user.next
ты сначала пишешь код, а потом думаешь, как его писать вообще.
Ну пока это действительно так. И имена функциям придумываю позже, да. Пока руководствуюсь лозунгом “главное начать” а там как кривая выведет. UPD. На самом деле я уже догадываюсь, как избавиться от копипасты, но для этого надо почти всю структуру программы переделать..
py.user.next
пример выпадения твоей программы, когда ей подаёшь строку 1000 всё время
А что это за чудо-юдо отладочные команды такие кстати? Это внешние какие-то модули или встроенные инструменты питона? Где почитать?

Отредактировано Palrom (Май 14, 2022 18:58:11)

Офлайн

#9 Май 14, 2022 19:02:41

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9873
Репутация: +  853  -
Профиль   Отправить e-mail  

Избежать частых повторений одного и того же кода

Palrom
А что это за чудо-юдо отладочные команды такие кстати?
Это Linux. Её надо поставить второй системой (чтобы винды в памяти не было, как при установке в виртуалку) и там заниматься программированием. Там есть много программ всяких, которых в винде нет. Программа yes посылает бесконечно строку y или заданную строку на вход другой программы. Она сделана специально, чтобы глушить программы, которые постоянно останавливают своё выполнение и у пользователя спрашивают yes/no и ждут ответ y? Чтобы отвечать y всё время и выполнение программы не останавливалось, сделана эта программа когда-то давно. В винде таких программ нет. Там есть только всякая бесполезная хрень.

Palrom
Если я раньше не кодил, то это не значит что я ни дня не работал и не решал сложные задачи.
Ты говоришь, что якобы будешь читать функции. Значит, ты не видел никогда программ, которые физически прочитать невозможно, потому что только читать ты их будешь несколько месяцев. Просто увеличь количество строк кода до тысячи, до пяти тысяч и ты не прочитаешь из них потом больше ста строк. Чтобы не перечитывать код, существуют юнит-тесты. Когда баг исправляется, не нужно перечитывать код, чтобы убедиться, что исправление бага не сломало ничего нового в коде; просто надо запустить юнит-тесты, которые пройдут по коду и заглянут в каждый его угол. А без юнит-тестов ты будешь десять раз исправлять баги и десять раз перечитывать весь код, чтобы гарантировать, что он правильно работает, что твоё исправление ни на что не повлияло.



Отредактировано py.user.next (Май 14, 2022 19:09:47)

Офлайн

#10 Май 15, 2022 11:28:21

Palrom
Зарегистрирован: 2022-04-21
Сообщения: 82
Репутация: +  5  -
Профиль   Отправить e-mail  

Избежать частых повторений одного и того же кода

py.user.next
Убунту подойдёт последняя? Гугл говорит, что это лучшее решение как для новичков так и для профи.

py.user.next
Чтобы не перечитывать код, существуют юнит-тесты
Это для меня пока, даже не тёмный лес а бетонная стена. Дайте время в линукс вползти хотя бы..
py.user.next
ты не видел никогда программ, которые физически прочитать невозможно, потому что только читать ты их будешь несколько месяцев
Ну таких больших, да, не видел. Кстати, может знаете где можно поглазеть на образцовый код? чтоб прям из палаты мер и весов, желательно по возрастанию сложности и не старый, без древнего формата, вроде ‘Hello, %s’ % name. UPD. Хотя вопрос наверное глуповат, достаточно открыть и почитать любую встроенную библиотеку..

Отредактировано Palrom (Май 15, 2022 11:59:40)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version