1

I'm writing my first program - it's an idiom generator, which combines individual elements from lists of random verbs, nouns, and pronouns (that I have entered) in Madlibs style and generates a humorous expression. This is a simplified version of my source code:

baseFunction = True
def mainFunction() :
  import random
  quest = input("Which language do you want it in? Type 'French' or 'English'. ")
  if quest == "French" or "french":
      verb = 
      #list of verbs I have manually entered
      noun = 
      #list of nouns I have manually entered
      pronoun = 
      #list of pronouns I have manually entered
      morenouns = 
      #list of nouns I have manually entered
      phrase = random.choice(verb) + random.choice(noun) + random.choice(pronoun) + random.choice(morenouns)
      print(phrase)
      print("Now, give it some meaning and use in the world!")

  elif quest == "English" or "english":
      verb = 
      #another list of verbs I have manually entered  
      noun = 
      #another list of nouns I have manually entered
      pronoun = 
      #another list of pronouns I have manually entered
      morenouns = 
      #another list of nouns I have manually entered
      phrase = random.choice(verb) + random.choice(noun) + random.choice(pronoun) + random.choice(morenouns)
      print(phrase)
      print("Now, invent some meaning for it and use it in the world!")
      f8 = input("Do you want to make another one? Say 'yes' if you do. ")
      if f8 == "yes" or "Yes":
          mainFunction()
      else:
          print("Thanks for playing!")
  else:
       print("Didn't quite catch that. Try again! (say yes!)")
       mainFunction()
def malif() :
   ques = input("Want to hear a funny idiom? Say 'yes' or 'no'. ")
   if ques == "yes" or "Yes":
       mainFunction()
   elif ques == "no" or "No":
       print("Wrong answer. Try again! (say yes)")
       malif()
   else:
       print("Didn't quite catch that. Say 'yes' or 'no'.")
while baseFunction :
    malif()
    mainFunction()

Essentially, I am asking the user whether they want to make an idiom, offering them a choice of language, generating the expression for them, and then asking them if they want to repeat the process. When I run the script in PyCharm, it runs the two functions in order (meaning, malif() first and then mainFunction(), as I have it at the end) but it does not pay any attention to my input (ex. if I say 'no' it runs the mainFunction anyway and will always do it in French even if I say 'English').

I used some of the tips discussed in this entry (Python - How to make program go back to the top of the code instead of closing). I think the problem lies calling the functions in their own definitions (ex. calling malif() if I answer 'no' to input 'ques', which is defined in malif() ). Yet, I have followed the tips discussed in the question that I linked and it is still not working the way that I want it to. Am I doing something wrong in formatting the code (ex. in terms of indentation) or if it is not obvious what I am doing wrong, is there a way for me to loop functions back to the beginning that was not suggested in the original question?

Thanks!

Joel Saarinen
  • 39
  • 1
  • 3

1 Answers1

0

First some tips when you work with strings as input. Python will make the difference between caps and non-caps letter, thus a good way to deal with strings is to lower() them first (or upper(), ...):

Example:

ques = input("Enter Yes or No: ")
ques = ques.lower()

if ques == "yes":
    # do something
elif ques == "no": 
    # do something else
else:
    # raise error

Now I feel like your code is build in a funny way. A good habit is to separate the import from the functions, from the main program. The 2 first will be imported if the module (file) is imported, while the last one will be played when the file is executed. To do so, you can use this:

# -*- coding: utf-8 -*-
"""
docstring of the module
"""

# Imports
import random
import os

# Functions
def f():
    return "Hello world"

# Main program
if __name__ == '__main__':
    # Calling the function, taking the inputs and so on

In the main program, it's rather useful to deal with the possibility that an exception is raised. Moreover, if you use the cmd to display your program, the cmd will close immediately when an error is raised. This syntax is quite useful:

if __name__ == '__main__':
    try:
        # Do stuff

    except:
        import sys
        print (sys.exc_info()[0])
        import traceback
        print (traceback.format_exc())

    os.system("pause") # for windows, else easy way is to have an empty input to freeze the cmd

Now your code. I would rework it this way:

# -*- coding: utf-8 -*-
"""
Docstring
"""

# Imports
import random
import os


# Functions
def build_a_phrase(language) :
    if language == "french":
        verb = ["vendre", "atterir", "attaquer", "jeter"]
        #list of verbs I have manually entered
        noun = ["arbre", "poisson", "chien"]
        #list of nouns I have manually entered
        pronoun = ["un", "les"]
        #list of pronouns I have manually entered
        morenouns = ["chat", "oiseau"]
        #list of nouns I have manually entered
        choices = [random.choice(verb), random.choice(noun), random.choice(pronoun), random.choice(morenouns)]
        phrase = " ".join(choices) # Add a space between the words

        return phrase

    elif language == "english":
        verb = ["...", "...", "..."]
        #another list of verbs I have manually entered  
        noun = ["...", "...", "..."]
        #another list of nouns I have manually entered
        pronoun = ["...", "...", "..."]
        #another list of pronouns I have manually entered
        morenouns = ["...", "...", "..."]
        #another list of nouns I have manually entered
        choices = [random.choice(verb), random.choice(noun), random.choice(pronoun), random.choice(morenouns)]
        phrase = " ".join(choices) # Add a space between the words

        return phrase


if __name__ == '__main__':
    try:
        # Parameters
        available_language = ["french", "english"]
        available_answers = ["yes", "no"]

        # Safety implementation of an input
        quest = ""
        i = 0
        while quest.lower() not in available_answers:
            quest = input("Want to hear a funny idiom? Say 'yes' or 'no'. ")
            i += 1
            if i == 2: # number of tries
                break

        if quest.lower() == "no":
            print ("I'm sure you meant yes.")

        language = ""
        i = 0
        while language.lower() not in available_language:
            language = input("Which language do you want it in? Type 'French' or 'English'.\n")
            i += 1
            if i == 2: # number of tries
                break

        while True:
            sentence = build_a_phrase(language)
            print (sentence)
            print ("Now, give it some meaning and use in the world!")

            f8 = ""
            i = 0
            while f8.lower()  not in available_answers:
                f8 = input("Do you want to make another one? Say 'yes' if you do. ")
                i += 1
                if i == 2: # number of tries
                    break

            if f8.lower() == "no":
                print("Thanks for playing!")
                break

    except:
        import sys
        print (sys.exc_info()[0])
        import traceback
        print (traceback.format_exc())

    os.system("pause")

Hope you'll get a few good tricks from this answer, and some good habits :) Not complete yet, when the input is wrong, an Error should be raised rather than waiting for the error resulting in the wrong input (i.e. a raise statement should be placed instead of the breaks)

Mathieu
  • 5,410
  • 6
  • 28
  • 55
  • Ok, I tried this in my IDE. Merci :). I have a few questions, though. For some reason, it is still only printing in French, even if I put "english" as the input (and added verbs, nouns, etc. for English). Is this an issue within build_a_phrase or in the __name__ if statement? Also, what exactly is the purpose of __name__ and main? Are they commands of the language, and how do they relate to what is under the 'except' statement? – Joel Saarinen Jul 06 '18 at 11:29
  • @JoelSaarinen For the language, that was my mistake... fixed it. I copied / paste your code, and forgot to change the `if / elif statement` with the variable language. – Mathieu Jul 06 '18 at 11:46
  • @JoelSaarinen Then for the `if __name__ == '__main__':`: it's going to check if the file is executed (launch through IDE, or double clicked on the .py file) or imported through and `import MyModule` statement where the file name is `MyModule.py`. With this, you can actually reuse your functions in other programs. The try / except statement is here to catch an error. What is after the except statement is only here to print the error in the cmd if you executed the file by double clicking on it. Through an IDE, it is not necessary. – Mathieu Jul 06 '18 at 11:48
  • @JoelSaarinen Main point is that the functions and class are define as general as possible (not the case yet in the example above) in order to be reused if needed. The parameters, and what you actually want to do with the function and class is performed in the main part. You were trying to do a recursivity to recall the function. This is not necessary here, simply doing a while loop which breaks out when you want to stop is enough. – Mathieu Jul 06 '18 at 11:49
  • @JoelSaarinen Final remark for the IDE, most of them have a outline window which propose you a high view of the program with every functions. It is capable of catching special comments, such as section titles: `# ---------------------------- Main program -----------------------------------`. It is really helpful on long program to navigate through it. Thus it's quite important to get good habits and to structure properly your program, with at least `Imports`, `Class`, `Functions`, and `Main`. – Mathieu Jul 06 '18 at 11:52