Форум сайта python.su
Дожив до четвертого десятка, решил заняться изучением программирования.
Цели устроится на работу в какой-нибудь IT гигант не стоит, т.к. реально понимаю , что в моем возрасте это вряд ли осуществимо в данной области, так скорее хобби(но очень интересное), но и говнокод писать не хочется. Если что-то делаешь, то делай правильно. В реальной жизни мне обратиться за советом не к кому. обращаюсь к вам.
В общем осваиваю Майкла Доусона “Программируем на питон”, дойдя и изучив главы Функции и Файлы ,для закрепления материала, собрал несколько ранее созданных учебных заданий и объединил их в одну программку, в которой пользователь с компьютером играет в игру “Угадай число”, а программа собирает результаты и выводит на экран.
В общем хотел попросить вас оценить получившийся продукт, указать на недостатки, недочеты. Вообще , правильно ли я усвоил понятия функций, все ли в порядке с логикой и т.д.
И ещё, это мой первый опыт в данной области вообще, так что, то что для ВАС тривиально, для меня тёмный лес)
Вот собственно, сам код.
import random, pickle, shelve, sys def acquaintance(question): """Знакомство с пользователем""" response = None while not response: response = input(question). title() return response def hallo_unit(name): print("""\t\t\tДобро пожаловать в игру \"УГАДАЙ ЧИСЛО\",""", name,""" Я буду загадывать число, а ты угадывать! Ты можешь задать диапазон чисел в которых будешь угадывать или оставить как есть, тогда диапазон будет от 1 до 100. у тебя всего 10 попыток! """) def ask_yes_no(question): """Задает вопрос с ответом "ДА" или "НЕТ".""" response = None while response not in ("ДА", "НЕТ"): response = input(question).upper() return response def game_interval(): """При желании пользователя меняет величину диапазона""" answer = ask_yes_no("\n\n\tВы желаете изменить диапазон чисел?") if answer == "НЕТ": interval = 100 else: try: interval = int(input("\n\n\tВведите величину диапазона, в котором будете отгадывать.")) except: print("\n\tВы ввели недопустимое значение, попробуем ещё разок!") interval = game_interval() return interval def ask_number(question, interval): """Просит ввести число из диапазона""" response = None while response not in range(1,interval): try: response = int(input(question)) if response not in range(1,interval): print("\n\tЭто число вне диапазона!") except: print("\n\tВы ввели недопустимое значение, попробуем ещё разок!") return response def user_game(interval, name): """Пользователь отгадывает число""" computer_choise = random.randrange(interval) + 1 score = 0 response = None while response != computer_choise : response = ask_number("\n\n\tНазывай число в заданном диапазоне.", interval) if response > computer_choise : score += 1 print("\n\tМеньше") elif response < computer_choise : score += 1 print("\n\tБольше") elif response == computer_choise : score += 1 print("\tМолодец, это действительно" , computer_choise) print("\tТы отгадал число всего за", score ,"шагов!") elif response <= 1 or response >= interval: print("Это число вне диапазона, пожалуйста введите другое!") if score == 10: print("\n\tНу ты , вообще, неудачник!") break records_list_4(score, interval, name) def records_list_4(score, interval, name): """Добавляет рекорды в виде консервированных списков на полке""" records = shelve.open("records.dat") interval = str(interval) if interval in records: name_records = records[interval] name_record = (score, name) name_records.append(name_record) records[interval] = name_records else: name_records = [] name_record = (score, name) name_records.append(name_record) records[interval] = name_records records.close() def print_record_2(): """Выводит на экран рекорды из файла""" print("\t\t\tСписок рекордов\n") print("""\t\tВ графе СЛОЖНОСТЬ указан интервал в котором велся поиск, чем больше тем сложнее, в графе РЕКОРД указано количество шагов за которое игрок угадал число, чем меньше тем лучше результат \n\n""") print("\t\tСЛОЖНОСТЬ\t\t\tИМЯ\t\tРЕКОРД\n\n") records = shelve.open("records.dat") for i in records: lvl_records = records[i] name_records = [] for j in lvl_records: score, name = j name_record = (score, name, i) name_records.append(name_record) name_records.sort() name_records = name_records[:3] for k in name_records: score, name, lvl, = k print("\t\t", lvl, "\t\t\t", name, "\t\t", score) print("\n\n") def computer_game(interval, ): """Компьютер отгадывает число""" print("""\n\n\t\t А теперь моя очередь, я буду отгадывать, Пиши больше или меньше, когда угадаю пиши - правильно. посмотрим кто быстрее?""") item = int(input("\n\tЗагадай число в заданном тобой диапазоне:")) name = "Компьютер" low = 1 hight = interval score = 0 user_response = "" response_copy = None while user_response != "Правильно": mid = (low + hight) // 2 response = range(interval + 1)[mid] print("\n\t", response) user_response = input("").title() if user_response == "Правильно": score += 1 print("\n\tЯ отгадал число всего за", score,"шагов!") elif user_response == "Больше": low = mid + 1 score += 1 elif user_response == "Меньше": hight = mid - 1 score += 1 else: print("\n\tПовторите пожалуйста - 'больше' или 'меньше'") if score == 10: print("\n\tВот я лошара!!!") break if response == response_copy: print("Вы либо забывчивый либо мошенник, я с такими не дружу! Прощайте!") sys.exit() response_copy = response records_list_4(score, interval, name) def main(): end_game = None while end_game != "НЕТ": name = acquaintance("\tДавай знакомиться,меня зовут Компьютер, а тебя?:") hallo_unit(name) interval = game_interval() user_game(interval, name) computer_game(interval) print_record_2() end_game = ask_yes_no("""\n\n\t\t\tЖелаете продолжить или и отдать ход другому, если ни то ни другое введите \"нет\".""") input("Нажмите Enter чтобы выйти") main()
Офлайн
Так, в целом алгоритм хороший, нет запутанностей, всё ясно происходит.
Тут плохая привычка экономии имён
Babay82interval = str(interval)
Babay82Не надо так делать, лучше придумывай новое имя каждый раз. Чем это закончится - однажды ты будешь смотреть на середину функции и видеть имя переменной, но что в ней находится в данный момент, ты не сможешь точно сказать, потому что будешь знать, что у тебя есть привычка переиспользования имён. Тебе будет казаться, что там одно, а там окажется другое, потому что ты забудешь, что что-то подменял там опять. А чтобы не забыть, что подменял, тебе всякий раз для понимания имён надо будет перечитывать весь код функции, чтобы точно знать, что в переменных. То есть одна привычка якобы экономии имён приводит к вырабатыванию другой привычки, которая затратна уже по времени. Ну и баги из-за таких подмен бывают так же часто, как и баги из-за копипаста.name_records = name_records[:3]
Babay82Если выполнитьexcept:
import this
Отредактировано py.user.next (Июль 13, 2021 00:01:51)
Офлайн
py.user.next
Спасибо, принял к сведению.
py.user.nextНапример, каким образом это можно реализовать?В общих чертах, чтоб не совершать в дальнейшем таких ошибок
Например, имя файла для базы данных у тебя зафиксировано, потому что ты не думаешь, что оно изменится. Но на эти мысли расчитывать нельзя, очень часто бывает так, что программа дописывается неожиданным образом и в ней появляются новые имена файлов с настройками, которые к старым именам уже не подходят (создают двусмысленности с ними). И чем проще поменять имя файла с данными в программе на другое, тем лучше. Завтра таких имён станет сто в программе и скорость их исправления будет очень сильно влиять на разработку. Переделывать полпроекта три дня и проверять каждое изменение при этом на безошибочность гораздо сложнее, чем переделать один файл во всём проекте за пять минут и без всяких проверок просто знать, что там всё в порядке.
Офлайн
Babay82Надо параметризировать функцию. То есть имя файла должно в неё подаваться, а не быть зашито внутри функции. Потом ты все такие имена собираешь в одном месте. И когда они в одном месте, ты можешь их “настраивать” (динамически присваивать им разные значения, в зависимости от условий запуска программы).
Например, каким образом это можно реализовать?
program -c myconfig.xml
Отредактировано py.user.next (Июль 13, 2021 00:06:02)
Офлайн
py.user.next
Спасибо, учту. Я просто до таких нюансов не дошел ещё, наверное. Пока осваиваюсь в новой, для себя области знаний.
Офлайн
def acquaintance(question): response = None while not response: response = input(question). title() return response
Офлайн
RodegastСпасибо, проект делал , после прохождения главы о файлах, и сразу импортировал модули т.к. изначально планировал записывать рекорды в виде списков со словарями, но не знаю как при создании нового рекорда сделать так что-бы автоматически создавалась бы новая переменная которая бы ссылалась на этот список, что-бы потом можно было к нему обратиться(чтоб не переписывать постоянно файл с рекордами), а с полками как то нашел выход .
Ст
import sys, pickle, shelve def instruction(): """Загружает инструкцию с игрой""" print("""\t\t\tДобро пожаловать в сказку! \tВам будут заданы вопросы и к ним предложены варианты ответов отвечаете правильно, получаете указанное количество баллов, если нет \t\tне получаете ничего. Желаю вам сказочной удачи!\n\n""") def ask_yes_no(question): """Задает вопрос с ответом "ДА" или "НЕТ".""" response = None while response not in ("ДА", "НЕТ"): response = input(question).upper() return response def acquaintance(question): """Знакомство с пользователем""" response = None while not response: response = input(question). title() return response def open_file(file_name, mode): """Открывает файл""" try: the_file = open(file_name, mode, encoding = "utf-8") except IOError as e: print("Невозможно открыть файл", file_name, ", работа программы будет завершена!\n") input("Нажмите Enter чтобы выйти\n\n") sys.exit() else: return the_file def next_line(the_file): """Возвращает в отформатированном виде очередную строку игрового файла""" line = the_file.readline() line = line.replace("/","\n") return line def next_block(the_file): """возвращает очередной блок данных из игрового файла""" category = next_line(the_file) question = next_line(the_file) point = next_line(the_file) if point: point = int(point[0]) answer = [] for i in range(4): answer.append(next_line(the_file)) correct = next_line(the_file) if correct: correct = correct[0] explanation = next_line(the_file) return category, question, answer, correct, explanation, point def welcome(title): """Приветствует игрока и сообщает ему тему игры""" print("\t\tДобро пожаловать в игру \"Викторина\"!\n") print("\t\t",title ,"\t\t") def records_list(name, score, file_name, mode): """Добавляет рекорды в файл""" records_list = open("records_list.dat", "ab") record = (score, name) pickle.dump(record, records_list) records_list.close() def demonstration_records(file_name, mode): """Выводит список рекордов на экран""" print_record =[] with open(file_name, mode) as records_list: while True: try: record = pickle.load(records_list) print_record.append(record) except: break print_record.sort(reverse=True) print_record = print_record[:3] for i in print_record: score, name = i print("\t\t", name,"\t\t", score, "баллов\n\n") def main(): instruction() end_game = None while end_game != "НЕТ": viktorin_file = open_file("Викторина.txt", "r") title = next_line(viktorin_file) welcome(title) name = acquaintance("Давайте знакомиться. Как вас зовут?:") score = 0 category = None while True: category, question, answer, correct, explanation, point = next_block(viktorin_file) if not category: break print(category) print(question) for i in range(4): print("\t", i + 1, "-", answer[i]) answer = input("Ваш ответ:") if answer == correct: print("Правильный ответ!", end = "") score += point else: print("Неправильный ответ!") print("Правильный ответ - ", correct) print(explanation) print("Ваш счет:", score,"\n\n") records_list(name, score, "records_list.dat", "ab") viktorin_file.close() print("Это был последний вопрос!") print("На вашем счету ", score, "очков") print("\n\n\t\t\tВОТ НАШИ РЕКОРДЕСМЕНЫ!!!\n\n") demonstration_records("records_list.dat", "rb") end_game = ask_yes_no("""\n\n\t\t\tЕсли желаете отдать ход другому игроку, введите \"да\" если желаете закончить игру введите \"нет\".""") main() input("Нажмите Enter чтобы выйти\n\n")
import sys def instruction(): """Загружает инструкцию с игрой""" print("""\t\t\tДобро пожаловать в сказку! \tВам будут заданы вопросы и к ним предложены варианты ответов отвечаете правильно, получаете указанное количество баллов, если нет \t\tне получаете ничего. Желаю вам сказочной удачи!\n\n""") def ask_yes_no(question): """Задает вопрос с ответом "ДА" или "НЕТ".""" response = None while response not in ("ДА", "НЕТ"): response = input(question).upper() return response def acquaintance(question): """Знакомство с пользователем""" response = None while not response: response = input(question). title() return response def open_file(file_name, mode): """Открывает файл""" try: the_file = open(file_name, mode, encoding = "utf-8") except IOError as e: print("Невозможно открыть файл", file_name, ", работа программы будет завершена!\n") input("Нажмите Enter чтобы выйти\n\n") sys.exit() else: return the_file def next_line(the_file): """Возвращает в отформатированном виде очередную строку игрового файла""" line = the_file.readline() line = line.replace("/","\n") return line def next_block(the_file): """возвращает очередной блок данных из игрового файла""" category = next_line(the_file) question = next_line(the_file) point = next_line(the_file) if point: point = int(point[0]) answer = [] for i in range(4): answer.append(next_line(the_file)) correct = next_line(the_file) if correct: correct = correct[0] explanation = next_line(the_file) return category, question, answer, correct, explanation, point def welcome(title): """Приветствует игрока и сообщает ему тему игры""" print("\t\tДобро пожаловать в игру \"Викторина\"!\n") print("\t\t",title ,"\t\t") def apps_record(name,score,file_name, mode): """Добавляет рекорд""" record = open("records.txt", "a", encoding="utf-8") score = str(score) line = ("Игрок \t" + name + "\t" + score + " \tбаллов\n") record.write(line) record.close() def sort_balls(rec_list): """Предоставляет аргумент для сортировки списка рекордов""" i = int(rec_list[-11:-9]) return i def print_records(file_name, mode): """Выводит рекорды на экран""" name_records = open("records.txt", "r", encoding="utf-8") records = name_records.readlines() records.sort(key=sort_balls, reverse=True) records = records[:5] for i in records: print(i) def main(): instruction() end_game = None while end_game != "НЕТ": viktorin_file = open_file("Викторина.txt", "r") title = next_line(viktorin_file) welcome(title) name = acquaintance("Давайте знакомиться. Как вас зовут?:") score = 0 category = None while True: category, question, answer, correct, explanation, point = next_block(viktorin_file) if not category: break print(category) print(question) for i in range(4): print("\t", i + 1, "-", answer[i]) answer = input("Ваш ответ:") if answer == correct: print("Правильный ответ!", end = "") score += point else: print("Неправильный ответ!") print("Правильный ответ", correct) print(explanation) print("Ваш счет:", score,"\n\n") apps_record(name,score,"records.txt", "a") print("t\t\t\n\nВОТ НАШИ РЕКОРДЕСМЕНЫ!!!\n\n") print_records("records.txt", "r") viktorin_file.close() print("Это был последний вопрос!") print("На вашем счету ", score, "очков") end_game = ask_yes_no("""\n\n\t\t\tЕсли желаете отдать ход другому игроку, введите \"да\" если желаете закончить игру введите \"нет\".""") main() input("Нажмите Enter чтобы выйти\n\n")
RodegastТ.к. в случае возврата None выпадет исключение?
Стремись к тому что бы функции возвращали только данные определённого типа.
Офлайн
> Т.к. в случае возврата None выпадет исключение?
Да. Например при вызове функции я ожидаю получить строку, а мне приходит None. В результате возникает ошибка TypeError. Это очень распространённая ситуация.
Офлайн
Rodegast
Да. Например при вызове функции я ожидаю получить строку, а мне приходит None. В результате возникает ошибка TypeError. Это очень распространённая ситуация.
Офлайн
> Ок, что должна вернуть функция если в процессе выполнения не удалось сформировать строку-ответ?
Пустую строку или вызвать исключение.
Отредактировано Rodegast (Апрель 11, 2019 11:40:31)
Офлайн