I am new to programming and one of the problems I have run across is structuring. I am learning Python (3) and am practicing by making a few practical programs. An issue I am running in to is how to get the right flow to the program. I find that as I write a function, I realize that I need it to lead to another function, so I end up calling the next function at the end of the function I'm writing. Then I realize that Python will read the code line-by-line, so I have to have the function I will be calling above the one I am actively writing. The effect is that I end up writing the program in reverse. For example:
#Replaces letters in chosen word with X's
def display_word():
selected_word = list(selected_word)
for x in selected_word:
x = "X"
print (x)
#Function that will display the welcome message when program launches
def start_screen():
user_input = input("Hello and welcome to Hang Man! If you would like to
start a game, please enter 'YES' now!")
user_input = user_input.upper()
if user_input == "YES":
display_word()
else:
print ("You're no fun!")
start_screen()
This is a little tid-bit that I have written in a hang-man program I am practicing with. I started out writing the start_screen function, then realized that I will need to call the display_word function within the start_screen function, but to do that, I will have to define the function before it is called, so I have to write the display_word function above the start_screen function, which effectively has me moving in reverse. My question is whether this is the way things go or if there is a better way to do things. It seems like writing the code in reverse is inefficient, but I am unsure if that is just my inexperience talking.
All functions in Python must be defined before they are used. That does not mean that the function has to be listed above the one it is called from.
The functions can be defined in any order. You just have to make sure the executable portions that start your program, like start_screen(), are called below where the function is defined.
In the case of your hangman program, you are perfectly safe to switch the order of the two functions.
In general, if you have all of your executable code following all of your function definitions, you are good to go to keep them in any order you choose!
Example:
This is perfectly ok. You can even switch them!
def fn1():
print('I am function 1')
fn2()
def fn2():
print ('I am function 2')
fn1()
This is bad!
fn1() #not defined yet!
def fn1():
print('I am function 1')
def fn2():
print ('I am function 2')
This is also bad!
def fn1():
print('I am function 1')
fn2() #not defined yet!
fn1()
def fn2():
print ('I am function 2')
Related
I read about "random" and it got me thinking about helping my kid in reading and writing by making a program where a word is shown and she needs to type it. Because it's a small program I could do it quite easliy with procedural programming, but to make it more 'attractive' to her I decided to fool around with tkinter.
Tkinter forces to create functions which can be called through 'command' and now I have a problem.. If I run the check() function, it doesn't get the variables from the dictee() function. I found several answer from nesting a function in a function (undefined variable problems), or passing arguments with return (ended up in recursion), using global (the list of words wouldn't empty) etc etc.. I couldn't get any of them working... I've been looking for answers, but I can't find the correct solution.. Anyone care to shed their light?
Thanks!
"""import nescessary."""
import sys
import random
def main():
"""Setting up the game"""
print("Aliyahs reading game.'\n")
begin = input("do you want to start? yes or no.\n\n")
if begin == "yes":
dictee()
def dictee():
"""Show random words and ask for input."""
words_correct = 0
words_wrong = 0
vocabulary = ['kip', 'hok', 'bal', 'muis', 'gat'
]
words_passed = []
while True:
if vocabulary == []:
print("\n\nThose were all the words.")
print("Words correct: %d" % words_correct)
print("words wrong: %d" % words_wrong)
one_more_time = input("Do you want to go again? yes or no")
if one_more_time == "no":
print("See you next time.")
input("\nPush enter to close.")
sys.exit()
else:
main()
word = random.choice(vocabulary)
print('\x1b[2J')
print("{}".format(word))
print("\n\n")
words_passed.append("{}".format(word))
vocabulary.remove("{}".format(word))
answer = input("Write the word you saw:\n\n")
check()
def check():
'''Cross check word shown with answer given'''
if answer == word:
print("Nice")
words_correct += 1
else:
print("2bad")
words_wrong += 1
try_again = input("\n\nContinue? yes or no\n ")
if try_again.lower() == "no":
exit_game()
else:
dictee()
def exit_game():
'''summarize results and exit after pushing enter'''
print("Words correct: %d" % words_correct)
print("Words wrong: %d" % words_wrong)
input("\nPress Enter to exit.")
sys.exit()
if __name__ == "__main__":
main()
Ive just made few changes here, and run it and got no errors because I dont know what to type in order to get the right results. Anyways all the changes are related to global and redefinition of values.
# say these outside all the functions, in the main block
words_correct = 0
words_wrong = 0
vocabulary = ['kip', 'hok', 'bal', 'muis', 'gat']
words_passed = []
def dictee():
global word, answer
..... #same bunch of codes
def check():
global answer, words_correct, words_wrong
.... #same bunch of codes
Why do we have to say global? Basically because when we define variables they either get defined on local scope or global scope, variables defined on main block(outside of all function) are on global scope, while inside functions are on local scope. Variables defined on global scope can be accessed anywhere and that on local can only be accessed from within where its defined.
Where do we have to use global? We say global where we define the variable or we redefine, or at least this is what I know of. We need to say global where we declare the variable, like, a = 'good', we also need to say global if we are changing it, a = 'bad' or a += 'day' because we are assigning a new value to it. Using global outside of all functions, on the main block, is useless.
Why are we declaring words_correct and words_wrong outside all functions? It is simply because if you declare and set its value to 0 inside dictee(), each time the function is run the value of those variables will change to 0, which means score will always be 0 or 1, so we define it once only, in the main block. Same logic applies to the two lists(vocabulary and words_passed), each time function runs they reset the list to the full list of words, so to get rid of that, just define it once in the main block.
I also think using parameters here might need re-structuring of your code as your calling both function from each other.
Note that we only say global on functions, out side functions all defined variables are open to global scope and can be accessed from anywhere in the code.
PS: This is just my understanding of global over the span of 4 months, do correct me if im wrong anywhere, thanks :D
enter image description hereI am a begineer in Python development and learning python on python 3.6
When I executed below code ,I expected it to terminate when first return statement is executed and I was expecting Output 4.
But It is iterating 3 times and giving output as 8.
As per my understanding as soon as return statement is executed it should come out of the function. Why this is not happening.
#!/bin/python3
def stockmax(prices):
# Write your code here
# Write your code here
count=0
profit=0
maximum=max(prices)
#print(maximum)
index_max=prices.index(maximum)
#print(index_max)
if len(prices)<=1:
return(profit)
else:
for i in range(len(prices)):
if i<index_max:
profit=profit-prices[i]
#print("profit if",profit)
count=count+1
#print("count is",count)
elif i==index_max:
#print(profit)
profit=profit+(prices[i]*count)
#print("profit elif",profit)
count=0
else:
profit=profit+stockmax(prices[i:])
return(profit) # should terminate on executing first return
x=(stockmax([5,4,3,4,5]))
print(x)
By calling stockmax inside of itself, you are opening up a new 'scope'. We can treat these as levels on a building. When you call it, you are essentially moving up a floor, or gaining a level. To get back to the ground floor, or the main 'scope' you need to go back through all of the lower floors. We can do this easily by using return a little bit sooner. In your code it would look a little like this:
def stockmax(prices):
count=0
profit=0
maximum=max(prices)
index_max=prices.index(maximum)
if len(prices)<=1:
return(profit)
else:
for i in range(len(prices)):
if i<index_max:
profit=profit-prices[i]
count=count+1
elif i==index_max:
profit=profit+(prices[i]*count)
count=0
else:
profit=profit+stockmax(prices[i:])
return(profit) # Use return here instead!
This would give us the desired output of 4.
Write a function list_files_recursive that returns a list of the paths of all the parts.txt files without using the os module's walk generator. Instead, the function should use recursion. The input will be a directory name.
Here is the code I have so far and I think it's basically right, but what's happening is that the output is not one whole list?
def list_files_recursive(top_dir):
rec_list_files = []
list_dir = os.listdir(top_dir)
for item in list_dir:
item_path = os.path.join(top_dir, item)
if os.path.isdir(item_path):
list_files_recursive(item_path)
else:
if os.path.basename(item_path) == 'parts.txt':
rec_list_files.append(os.path.join(item_path))
print(rec_list_files)
return rec_list_files
This is part of the output I'm getting (from the print statement):
['CarItems/Honda/Accord/1996/parts.txt']
[]
['CarItems/Honda/Odyssey/2000/parts.txt']
['CarItems/Honda/Odyssey/2002/parts.txt']
[]
So the problem is that it's not one list and that there's empty lists in there. I don't quite know why this isn't not working and have tried everything to work through it. Any help is much appreciated on this!
This is very close, but the issue is that list_files_recursive's child calls don't pass results back to the parent. One way to do this is to concatenate all of the lists together from each child call, or to pass a reference to a single list all the way through the call chain.
Note that in rec_list_files.append(os.path.join(item_path)), there's no point in os.path.join with only a single parameter. print(rec_list_files) should be omitted as a side effect that makes the output confusing to interpret--only print in the caller. Additionally,
else:
if ... :
can be more clearly written here as elif: since they're logically equivalent. It's always a good idea to reduce nesting of conditionals whenever possible.
Here's the approach that works by extending the parent list:
import os
def list_files_recursive(top_dir):
files = []
for item in os.listdir(top_dir):
item_path = os.path.join(top_dir, item)
if os.path.isdir(item_path):
files.extend(list_files_recursive(item_path))
# ^^^^^^ add child results to parent
elif os.path.basename(item_path) == "parts.txt":
files.append(item_path)
return files
if __name__ == "__main__":
print(list_files_recursive("foo"))
Or by passing a result list through the call tree:
import os
def list_files_recursive(top_dir, files=[]):
for item in os.listdir(top_dir):
item_path = os.path.join(top_dir, item)
if os.path.isdir(item_path):
list_files_recursive(item_path, files)
# ^^^^^ pass our result list recursively
elif os.path.basename(item_path) == "parts.txt":
files.append(item_path)
return files
if __name__ == "__main__":
print(list_files_recursive("foo"))
A major problem with these functions are that they only work for finding files named precisely parts.txt since that string literal was hard coded. That makes it pretty much useless for anything but the immediate purpose. We should add a parameter for allowing the caller to specify the target file they want to search for, making the function general-purpose.
Another problem is that the function doesn't do what its name claims: list_files_recursive should really be called find_file_recursive, or, due to the hardcoded string, find_parts_txt_recursive.
Beyond that, the function is a strong candidate for turning into a generator function, which is a common Python idiom for traversal, particularly for situations where the subdirectories may contain huge amounts of data that would be expensive to keep in memory all at once. Generators also allow the flexibility of using the function to cancel the search after the first match, further enhancing its (re)usability.
The yield keyword also makes the function code itself very clean--we can avoid the problem of keeping a result data structure entirely and just fire off result items on demand.
Here's how I'd write it:
import os
def find_file_recursive(top_dir, target):
for item in os.listdir(top_dir):
item_path = os.path.join(top_dir, item)
if os.path.isdir(item_path):
yield from find_file_recursive(item_path, target)
elif os.path.basename(item_path) == target:
yield item_path
if __name__ == "__main__":
print(list(find_file_recursive("foo", "parts.txt")))
I have what looks to me like a completely normal function. However, for some reason, the function is exiting without executing any of the if/else statements.
def MainFunction():
shapeToSolve = input("What kind of shape are you calculating?")
print(shapeToSolve, "wtf")
if shapeToSolve == "Square":
solveSquare()
elif shapeToSolve == "Circle":
solveCircle()
elif shapeToSolve == "Triangle":
solveTriangle()
Notice the print(shapeToSolve, "wtf") block. I did this to see what's being returned from the function. Despite the fact that I have no other operation happening on shapeToSolve() anywhere else in the program, for some reason this prints "g wtf" to the console.
How is shapeToSolve() getting the letter "g" passed in as its input when the console isn't even allowing input before exiting the function?
Aside from the other functions that are called, this is the only other code in the program:
print("Hello! Welcome to the Geometry Calculator.")
MainFunction()
There isn't any problem. Are you sure you didn't just accidentally type "g" as your input?
i'm running into "out of range" while hitting enter and imputing single words. I understand why they are out of range, i just can't find how to fix the issue. this is my code:
commands = {
'help': help,
'exit': exit,
'look': look,
'stats': thePlayer.printStats,
's':thePlayer.move_South}
def runCmd(cmd, args, player):
commands[cmd](args, player)
def help(args):
print(commands)
def play():
main1()
World.loadTiles()
#These lines load the starting room and display the text
room = World.tileExists(player.locationX, player.locationY)
print(room.introText())
while player.isAlive():
room = World.tileExists(player.locationX, player.locationY)
room.modifyPlayer(player)
# Check again since the room could have changed the player's state
if player.isAlive():
print("\nHp:%d\%d Mp:%d\%d\n"%(player.hp,player.maxHp,player.mp,player.maxMp))
print(room.printEnemy())
availableActions = room.availableActions()
for action in availableActions:
print(action)
actionInput = input('Action: ')
action = actionInput.lower()
action = action.split()
print(action)
if action[0] in commands:
runCmd(action[0],action[1], player)
i realize i'm not passing an "action[1]" and that just hitting enter isn't in "commands" causing my error. i'm new to coding so creating a game is how i'm teaching myself.
i'm trying to get to where i can type: enter, single word (help, stats), double words (look rat), other things with more words ( buy big sword) and so on. any help on how i can code this correctly?
How about testing
len(action)
before calling runCmd? Thus, you can know if there are one word, two words, or more than two words.
If there is only one word, you can call:
runCmd(action[0], None, player)
If there are two words, you can call your current function. If there are more than two words, it's a bit tricky. You can pass the whole action variable. Then, the called function has to know how many parameters it needs.