6
\$\begingroup\$

So I have encountered a problem with asking user for input to be exact what is the best way to ask yes/no, for example accepting y / n and why is if i == no or i == c_n: not working? What are other mistakes or bad practices that I'm doing here?

i = input('yes/no: ')
success = "Success"
exit = "EXIT"
error = 'ERROR'
yes = 'yes'
c_y = 'y'
c_n = 'n'
no = 'no'

if i.lower().strip() == yes:

    i = input('Continue: ').lower().strip()
    if i == yes or i == c_y:
        print('{}'.format(success))
    if i == no or i == c_n:
        print('{}'.format(exit))
else:
    print('{}'.format(error))

Solution to my problem:

success = "Success"
exit = "EXIT"
error = 'ERROR'
yesAnswers = ['yes', 'y', 'sure!', ''];
noAnswers = ['no', 'n', 'nope']

answer = input('Yes/No or Enter: ').lower().strip()

if answer in yesAnswers:
    print(success)
elif answer in noAnswers:
    print(exit)
else:
    print(error)

Full code:

class characters:

    def __init__(self, title, character_name, power_score, biography):
        self.title = title
        self.character_name = character_name
        self.power_score = '| ' + 'Power score - ' + power_score + ' -\n'
        self.biography = biography

    def title_name(self):
        print('{} {}'.format(self.title,self.character_name))

    def characters_data(self):
        print('{} {} {} {}'.format(self.title, self.character_name, self.power_score, self.biography))


B_Cider = characters('Barbarian', 'Cider', '4854', 'Not much is known about this character')
L_Cido = characters('Lord', 'Cido', '7910', 'Not much is known about this character' )

# Y(Height) of ascii-art
z = 12
for x in range(z):
    print("-" * (z-x) + "*" * x + " " * x + "-" * (z-x))
# ...............

answer = input('Are you ready to play? (Yes/No or Enter) : ').lower().strip()
first_selection = "Do you want to be a Hero? (Yes/No or Enter) : "
not_Ahero = "\nYou have selected not to be a hero\n____\nYour characters profile:"
Ahero = "\nYou have selected to be a hero\n____\nYour characters profile:"
error = 'ERROR'
yesAnswers = {'yes', 'y', 'sure!', 'yea', 'yeah', 'ye', 'si', ''}
noAnswers = {'no', 'n', 'nope', 'nah', 'not'}

if answer in yesAnswers:
    answer = input(first_selection).lower().strip()
    if answer in yesAnswers:
        print(Ahero)
        print(characters.characters_data(B_Cider))
    if answer in noAnswers:
        print(not_Ahero)
        print(characters.characters_data(L_Cido))
else:
    print(error)
\$\endgroup\$
4
  • 2
    \$\begingroup\$ Does this exist as part of a larger program? If so, please show the full source. \$\endgroup\$
    – Reinderien
    Commented Mar 21, 2021 at 16:34
  • \$\begingroup\$ Updated post with full source. \$\endgroup\$
    – HTTP402
    Commented Mar 21, 2021 at 21:45
  • \$\begingroup\$ Off-topic, but uh. There's no such thing as an HTML402. Maybe you meant an HTTP 402. \$\endgroup\$
    – Reinderien
    Commented Mar 22, 2021 at 20:00
  • 1
    \$\begingroup\$ Yes and yes - HTTP Status Code 402 would make more sense \$\endgroup\$
    – HTTP402
    Commented Mar 22, 2021 at 20:02

2 Answers 2

4
\$\begingroup\$
  • characters should be named Character
  • Add some type hints
  • Use f-strings
  • Use int or float for power score, not str
  • Use a @property where appropriate
  • As-is, there isn't a lot of advantage to separating your prompt strings into variables
  • For the data method, don't force a print - just return a string and print at the outer level
  • Add a main
  • Square brackets around an input choice implies that it is the default to be selected on 'enter'
  • Simplify your yes/no check to only care about the first letter; anything more complicated isn't all that useful
  • Add an input validation loop

Suggested:

class Character:
    def __init__(
        self,
        title: str,
        name: str,
        power_score: int,
        biography: str = 'Not much is known about this character',
    ):
        self.title = title
        self.name = name
        self.power_score = power_score
        self.biography = biography

    @property
    def full_name(self) -> str:
        return f'{self.title} {self.name}'

    @property
    def data(self) -> str:
        return (
            f'{self.title} {self.name} | Power score - {self.power_score} -\n'
            f'{self.biography}'
        )


def ascii_art():
    # Y(Height) of ascii-art
    z = 12
    for x in range(z):
        hyphens = "-" * (z-x)
        print(hyphens + "*" * x + " " * x + hyphens)


def input_yesno(prompt: str) -> bool:
    full_prompt = f'{prompt} ([Yes]/No): '
    while True:
        answer = input(full_prompt).strip()
        if answer == '':
            return True

        answer = answer[0].lower()
        if answer == 'y':
            return True
        if answer == 'n':
            return False
        print('ERROR')


def main():
    ascii_art()
    if not input_yesno('Are you ready to play'):
        return

    is_hero = input_yesno('Do you want to be a Hero')
    print('\nYou have selected', end=' ')
    if is_hero:
        print('to be a hero')
        character = Character('Barbarian', 'Cider', 4854)
    else:
        print('not to be a hero')
        character = Character('Lord', 'Cido', 7910)

    print("\nYour character's profile:")
    print(character.data)


if __name__ == '__main__':
    main()
\$\endgroup\$
2
\$\begingroup\$

Your updated code looks way cleaner already. Your membership tests answer in yesAnswers / answer in noAnswers are obviously not performance critical here. But in general (especially on large datasets) it's preferrable to use sets for membership tests since they can provide membership information in constant instead of linear time.

Examples:

yesAnswers = {'yes', 'y', 'sure!', ''}

or

noAnswers = set('no', 'n', 'nope')
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.