Witam,
Mam takie klasy i chcę aby wyrażenie not subject.calendar.events
było obliczanie w trakcie działania programu
# plik history/menu.py
class HistoryQuizMenu(Menu):
def __init__(self, subject):
super(HistoryQuizMenu, self).__init__(title='History quiz')
self.subject = subject
self.calendar = subject.calendar
self.failed_when = not subject.calendar.events # <- chodzi mi o to wyrażenie
self.failed_when_msg = 'event list is empty'
self.add_item('Ask about events dates', self.ask_about_events_dates)
self.add_item('Ask about events centuries', self.ask_about_events_centuries)
self.add_item('Ask about events epochs', self.ask_about_events_epochs)
def ask_about_events_dates(self):
take_quiz(self.subject, HistoryTest(HistoricalDateQuestion, self.calendar.events))
def ask_about_events_centuries(self):
take_quiz(self.subject, HistoryTest(HistoricalCenturyQuestion, self.calendar.events))
def ask_about_events_epochs(self):
take_quiz(self.subject, HistoryTest(HistoricalEpochQuestion, self.calendar.events))
# plik utils/menu.py
import sys
class MenuItem:
def __init__(self, name, action):
self.name = name
self.action = action
def __str__(self):
return self.name
def __repr__(self):
return f'MenuItem(name={self.name}, action={self.action})'
def invoke(self):
self.action()
class Menu:
def __init__(self, title, fancy_banner=True, banner_fill='#', return_handlers=None, quit_handlers=None,
quit_option_name='Quit', failed_when=False, failed_when_msg='conditional failed'):
self.title = title
self.fancy_banner = fancy_banner
self.banner_fill = banner_fill
self.return_handlers = [] if return_handlers is None else return_handlers
self.quit_handlers = [] if quit_handlers is None else quit_handlers
self.active = True
self.items = []
self.__quit_option_name = quit_option_name
self.failed_when = failed_when
self.failed_when_msg = failed_when_msg
self.items.append(MenuItem('Quit', self.quit))
def __print_banner(self, fill):
if self.fancy_banner:
min_length = max([len(item.name) for item in self.items]) + 3 + len(str(len(self.items)))
banner_size = len(self.title) + 4 if len(self.title) + 4 > min_length else min_length
print(fill * banner_size)
print(f'{fill} {self.title:^{banner_size - 4}} {fill}')
print(fill * banner_size)
else:
print(self.title)
def __print_items(self):
for index, item in enumerate(self.items):
print(f'[{index}] {item}')
def __read_choice(self, prompt='Your choice: ', error='Error: invalid choice!'):
while True:
try:
choice = int(input(prompt))
if choice < 0:
raise ValueError(error)
return self.items[choice]
except (IndexError, ValueError):
print(error)
print('Valid choices are:')
self.__print_items()
@property
def quit_option_name(self):
return self.__quit_option_name
@quit_option_name.setter
def quit_option_name(self, value):
item = self.items.pop(-1)
item.name = value
self.items.append(item)
self.__quit_option_name = value
def quit(self):
self.active = False
if self.quit_handlers:
for func in self.quit_handlers:
try:
func()
except Exception as e:
print(f'Exception at the quit handler function {func.__name__}: "{e}".', file=sys.stderr)
def register_return_handler(self, func):
self.return_handlers.append(func)
def unregister_return_handler(self, func):
self.return_handlers.remove(func)
def register_quit_handler(self, func):
self.quit_handlers.append(func)
def unregister_quit_handler(self, func):
self.quit_handlers.remove(func)
def add_item(self, title, action):
self.items.append(MenuItem(title, action))
self.items.append(self.items.pop(-2))
def remove_item(self, index):
del self.items[index]
def add_submenu(self, menu, item_name=None):
if item_name is None:
item_name = menu.title
menu.quit_option_name = 'Back'
self.add_item(item_name, menu.loop)
def loop(self):
if self.failed_when:
print(f'Error: {self.failed_when_msg}.')
return
self.active = True
while self.active:
self.__print_banner(self.banner_fill)
self.__print_items()
choice = self.__read_choice()
try:
choice.invoke()
except Exception as e:
print(f'Exception at the invoke function: "{e}", menu choice: "{choice.name}".', file=sys.stderr)
if self.return_handlers:
for func in self.return_handlers:
try:
func()
except Exception as e:
print(f'Exception at the return handler function {func.__name__}: "{e}".', file=sys.stderr)
Mój problem polega na tym, że kiedy dodam nowe wydarzenie i zechcę zrobić quiz to w zmiennej failed_when nadal pozostaje wartość wyrażenia, która została jej przypisana przy inicjalizacji klasy.
Kod:
#!/usr/bin/env python3
import atexit
from subjects.history.base import Calendar, HistorySubject
from ui.utils.menu import Menu
from ui.settings.menu import SettingsMenu
from ui.subjects.history.menu import EpochManagerMenu, EventManagerMenu, HistoryQuizMenu
# TODO: implement update_db method
def update_db():
pass
def main():
atexit.register(update_db)
menu = Menu('Main menu', fancy_banner=True)
default_calendar = Calendar(name='Calendar')
history_subject = HistorySubject(calendar=default_calendar)
menu.add_submenu(HistoryQuizMenu(history_subject))
menu.add_submenu(EventManagerMenu(history_subject))
menu.add_submenu(EpochManagerMenu(history_subject))
menu.add_submenu(SettingsMenu(history_subject))
menu.loop()
print('Good bye!')
if __name__ == '__main__':
main()
Podam może aktualne wejście i wyjście:
#################
# Main menu #
#################
[0] History quiz
[1] Manage events
[2] Manage epochs
[3] Settings
[4] Quit
Your choice: 0
Error: event list is empty.
#################
# Main menu #
#################
[0] History quiz
[1] Manage events
[2] Manage epochs
[3] Settings
[4] Quit
Your choice: 1
###########################
# Manage events #
###########################
[0] Add event
[1] Remove event
[2] Search events at date
[3] Search events at period
[4] Search events at epoch
[5] Display events
[6] Back
Your choice: 0
Enter a year in the format year [BCE|CE]. Part BCE|CE is optional.
If era won't be specified, then default value will be CE.
> 150
Enter an event description: wydarzenie 1
Are you sure you want to add this event?
Your choice [y|n]
> y
Event added.
###########################
# Manage events #
###########################
[0] Add event
[1] Remove event
[2] Search events at date
[3] Search events at period
[4] Search events at epoch
[5] Display events
[6] Back
Your choice: 0
Enter a year in the format year [BCE|CE]. Part BCE|CE is optional.
If era won't be specified, then default value will be CE.
> 610
Enter an event description: wydarzenie 2
Are you sure you want to add this event?
Your choice [y|n]
> y
Event added.
###########################
# Manage events #
###########################
[0] Add event
[1] Remove event
[2] Search events at date
[3] Search events at period
[4] Search events at epoch
[5] Display events
[6] Back
Your choice: 6
#################
# Main menu #
#################
[0] History quiz
[1] Manage events
[2] Manage epochs
[3] Settings
[4] Quit
Your choice: 0 <- tu pojawia się bug w programie
Error: event list is empty.
#################
# Main menu #
#################
[0] History quiz
[1] Manage events
[2] Manage epochs
[3] Settings
[4] Quit
Your choice: 4
Good bye!
Gdzie pojawia się problem zaznaczyłem odpowiednio.