I'm following a book "functional python programming" by David Mertz, i have come across a following piece of code.
def echo_IMP():
while 1:
x = raw_input("IMP -- ")
if x == 'quit':
break
else:
print(x)
The functional version of above code seems like this:
def identity_print(x):
print(x)
return x
echo_FP = lambda: identity_print(raw_input("IMP -- "))=='quit' or echo_FP()
echo_FP()
How this identity_print() is being called again ?
what does this or expression actually doing ?
echo_FP = lambda: identity_print(raw_input("IMP -- "))=='quit' or echo_FP()
The order of execution is:
raw_input("IMP -- ") returns users input (let's call in input)
result of raw input goes to identity_print(input) - which prints input and returns it
the remainder of the function is input=='quit' or echo_FP(). The way A or B works is:
if A:
return A
else:
return B
So, if input=='quit' (that is A), it returns True and ends there, otherwise the whole lambda is executed again (echo_FP()).
You are creating a function with some conditions inside it. in other words, you are saying "call identity_print, and if the result is 'quit': the condition is validated, if not: call me again"
The echo_FP function:
echo_FP = lambda: identity_print(raw_input("IMP -- "))=='quit' or echo_FP()
has this kind of behavior:
def echo_FP():
var = identity_print(input("IMP -- "))
if var == 'quit':
pass
else:
echo_FP()
The recursion comes when identity_print doesn't returns quit because the function executes the or condition which is a call to echo_FP
Here we are defining one lambda function with no actual input but the statement is actually a function call to identity_print() ..whose input is entered by user. That is why we are calling it like this echo_FP() with no input.
As per the functionaliy of 'or' operator it will search for first right match. so in this case if user enters anything other than 'quit' then the first match fails (identity_print(raw_input("IMP -- "))=='quit will result False) so it goes and executes echo_FP(). so till the point user keeps on entering anything other than 'quit' , it will keep on calling echo_FP(). The moment you enter 'quit' it will return true and comes out of it.
Related
I want to define a function which takes an input from the user, returns the length of the input string and prints this out.
I have the following code:
def str_length(my_string):
my_string = input("give me a string: ")
return len(my_string)
print(str_length(my_string))
This code does not work. When I exchange the parameter in the last line to "hello" the code works.
def str_length(my_string):
my_string = input("give me a string: ")
return len(my_string)
print(str_length("hello"))
Can anyone explain to me why the first code does not work while the second one works? I am totally confused :-(
You should define it like this:
def str_length():
my_string = input("give me a string: ")
return len(my_string)
print(str_length())
When you call the function with my_string you get NameError because there is no my_string define yet. you define it inside the function. (After you call it). that is the reason.
Thanks to #prashantrana, You can also define your function like this:
def str_length(my_string):
return len(my_string)
my_string = input("give me a string: ")
print(str_length(my_string))
The difference here is that we get input from user out of the function scope, the pass it to function.
As #UnholySheep pointed out, your function is taking a parameter it doesn't seem to need.
Let's break it down
Def str_length (): # start of function definition
# promt user for the string and put it in the variable "my _string"
my_string = input ("give me a string:")
# return the length of input string
return len(my_string)
print(str_length ()) # the function is called inside print () and therefore returns the length of the user input string to print () to be printed on screen.
Good day everyone, I'm fairly new to python and I had some questions regarding creating menus...
So I recently made a menu using the while loop, and it works like it's supposed to. My question, however, is whether or not it's possible to create a menu using a for loop. I know a for loop is used when you want something to cycle for an x amount of times.
I tried searching for the answer already, but I couldn't really find anything related. If anyone can point me in the right direction, I'd appreciate it.
Here is my menu using "while":
def mainMenu():
print("SELECT A FUNCTION")
print("")
print("e1- Calculate The Area Of A Sphere")
print("e2- Calculate The Volume Of A Cube")
print("e3- Multiplication Table")
print("e4- Converting Negatives To Positives")
print("e5- Average Student Grades")
print("e6- Car Sticker Color")
print("e7- Exit")
print("")
while True:
selection = input("Enter a choice: ")
if(selection == "e1"):
e1()
break
elif(selection == "e2"):
e2()
break
elif(selection == "e3"):
e3()
break
elif(selection == "e4"):
e4()
break
elif(selection == "e5"):
e5()
break
elif(selection == "e6"):
e6()
break
elif(selection == "e7"):
print("Goodbye")
break
else:
print("Invalid choice. Enter 'e1'-'e7'")
print("")
mainMenu()
My guess is that your instructor wanted you to use a generator. Based on your question, I'm going to assume that you are not familiar with generators. If you already know about them, skip to the second section, otherwise it might be worth your time to learn about them first.
Generators
In short, a generator acts like a function but instead of using a return statement it uses a yield statement. Calling next on a generator will run it until it reaches a yield statement and then suspend the process (and save the state of the generator, as opposed to normal functions, which typically don't save state between calls) until next is called on the generator again, at which point the control flow will be resumed where the generator left off.
The following code should give you an idea of how generators work:
# Define a generator function. This function will return our generator iterator.
def test_gen():
numCalls = 0
print("Start. This code is only executed once.")
while numCalls < 10:
print("Entering while loop.")
yield("Yielding. numCalls = %d." %(numCalls))
numCalls += 1
print("Resuming control flow inside generator.")
print("End. This code is only executed once.")
yield("Last yield.")
# End test_gen.
# Test the behavior of our generator function.
def run_test_gen():
# Create generator iterator by calling the generator function.
gen = test_gen()
# Continuously get the next value from the gen generator.
while True:
# If the generator has not been exhausted (run out of values to yield), then print the next value.
try:
print(next(gen))
# Break out of the loop when the generator has been exhausted.
except StopIteration:
print("Generator has been exhausted.")
break
# End run_test_gen.
run_test_gen()
If you want to know more about generators I'd check out the Python docs and the explanation Jeff Knupp has here.
Making a Menu With a Generator and a for Loop
Now that we know about generators, we can use them to create a menu based on a for loop. By placing a while True statement inside of a generator we can create a generator that yields an infinite number of values. Since generators are iterable, we can iterate over the yielded values in a for loop. See the below code for an example.
def infinite_gen():
"""
First, create a generator function whose corresponding generator iterator
will yield values ad infinitum. The actual yielded values are irrelevant, so
we use the default of None.
"""
while True:
yield
# End infinite_gen.
def print_str_fun(string):
"""
This function simply returns another function that will print out the value
of string when called. This is only here to make it easier to create some
mock functions with the same names that you used.
"""
return(lambda : print("Calling function %s." %(string)))
# End print_str.
# Create a tuple of the function names that you used.
fun_name_tuple = ('e%d' %(ii) for ii in range(1, 7))
# Create a dictionary mapping the function names as strings to the functions themselves.
fun_dict = {fun_name: print_str_fun(fun_name) for fun_name in fun_name_tuple}
# Add the e7 function separately because it has distinct behavior.
fun_dict['e7'] = lambda : print("Goodbye.")
def mainMenu():
"""
Example mainMenu function that uses for loop iterating over a generator
instead of a while loop.
"""
# Create our infinite generator.
gen = infinite_gen()
# Iterate over the values yielded by the generator. The code in the for loop
# will be executed once for every value yielded by the generator.
for _ in gen:
# Get function name from user input.
selection = input("Enter a choice: ")
# Try to call the function selected by the user.
try:
fun_dict[selection]()
break
# Print a note to user and then restart mainMenu if they supplied an
# unsupported function name.
except KeyError:
print("Invalid choice. Enter 'e1' - 'e7'.")
print()
mainMenu()
# End mainMenu.
# Allows one to run the script from the command line.
if __name__ == '__main__':
mainMenu()
No this isn't homework but it is on our study guide for a test. I need to understand the role the return statement plays and the role recursion plays. I don't understand why the function doesn't break after x = 1.
def thisFunc(x):
print(x)
if x>1:
result=thisFunc(x-1)
print(result)
return x+1
Sorry, I understand how elementary this is but I could really use some help. Probably why I can't find an explanation anywhere...because it's so simple.
edit: Why does it print out what it does and what and why is the value of x at the end? sorry if I'm asking a lot I'm just frustrated
When you enter the function with a value n>1 it prints the current value, and then calls it's self with n-1. When the inner function returns it returns the value n - 1 + 1 which is just n. Hence, the function prints out the value n twice, once before the inner recursion and once after.
If n == 1, which is the base case, the function only prints 1 once and does not call it self again (and hence does not get result back to print). Instead it just returns, hence why 1 is only printed once.
Think of it like an onion.
calling thisFunc(n) will result in
n
# what ever the output (via print) of thisFunc(n-1) is
n
I don't understand why the function doesn't break after x = 1.
But it does:
>>> ================================ RESTART ================================
>>> x = 1
>>> def thisFunc(x):
print("Function called on x-value: ", x)
if x > 1:
result = thisFunc(x-1)
print(result)
return x+1
>>> thisFunc(x)
Function called on x-value: 1
2
>>>
edit: Why does it print out what it does and what and why is the value of x at the end?
Well, it prints it out because you're telling it to. Try following the value of x as you go through the function ("x is one, one is not bigger than 1; return 1+1. Ok. [new case] x is two, two is bigger than 1..." and so on).
return and recursion are part and parcel of programming; return statements designates the end of a function (even if you might have several lines more of code) and they also pass data back to whatever asked them for it. In your case you're asking "what happens when x is 1, given these rules?"; the returned data is your answer.
Recursion is simply the matter of letting the function call itself, should it (you) need to. You simply tell the program that "hey, as long as x is bigger than 1, call this function [that just so happens to be the same function initially called] on it and let it do its thing". To get a better understanding of your function I'd suggest that you add the line "Function called on x-value: " to the first print statement inside the function, or at least something that lets you identify which printed line is x and which is result.
For a more in-depth explanation on recursion, I recommend Recursion explained with the flood fill algorithm and zombies and cats
I'm fairly new to python (coding in general really), but I mostly grasp what's put in front of me. I'm trying to create an input that will only accept integers, so I put together the following function:
def askFor(request):
"""Program asks for input, continues to ask until an integer is given"""
num = ' '
while (isinstance(num, int) == False):
num = input(request)
else:
return num
it works fine when i enter a number, but anything else breaks it instead of looping it back. Am I missing an element, or am I just best off to go with
str(input('wargharble: '))
You are on the safer side with raw_input in Python 2, because it will always return a string, whereas input will try to evaluate the given string, which is dangerous.
def askFor(prompt):
""" ask for input, continues to ask until an integer is given
"""
number = None
while True:
try:
number = int(raw_input(prompt))
break
except ValueError:
pass # or display some hint ...
print(number) # or return or what you need ...
The problem is that input() returns the raw user input evaluated as a python expression. So when you input something like "someinput" on the console here is what happens:
The raw input is captured from the console as a string
That string is then parsed as a python expression (so imagine you simply type this string into your program, in this case, it becomes a variable with the name "someinput"
When isinstance() is called on this python expression, the python interpreter can't find a variable named "someinput" which is defined - so it throws an exception.
What you really want to do is use raw_input(), this will return a string representing the user's input. Since you are receiving a string from the console now though, you need some way of checking if a string is an int (because isinstance will always return a string)
Now to determine if the string is a number, you could use something like isdigit() - but be careful - this function will validate any string that contains only digits (so 0393 would be valid).
Here are the corrections that need to be made:
def askFor(request):
"""Program asks for input, continues to ask until an integer is given"""
num = ' '
while (num.isdigit() == False):
num = raw_input(request)
else:
return num
This is because input() is failing on non-integer input (this has to do with the fact that input() is calling eval() on the string your inputting (see python builtins).
raw_input() does not. (in fact, input() calls raw_input())
Try this instead:
while True:
num = raw_input(request)
if num.isdigit():
break
The isdigit() function checks to see if each character in a string is a digit ('0' - '9')
input evaluates whatever's typed in as Python code, so if the user types something non-sensical in, it'll produce an error. Or worse, it can run arbitrary commands on your computer. Usually, you want to use raw_input and convert the string value it returns safely yourself. Here, you just need to call int on the string, which can still produce an error if the user enters a non-int, but we can handle that by looping.
And voila:
def read_int(request):
while True:
try:
return int(raw_input(request))
except ValueError:
pass
Note, there's no need for break or else; just return the value once you have parsed it successfully!
Well first off, your indentation if a bit off (the while loop's indentation level does not match the previous level).
def askFor(request):
"""Program asks for input, continues to ask until an integer is given"""
num, isNum = '', False # multiple assignment
while not isNum:
num = input(request)
if type(num) in (int, long): # if it is any of these
isNum = True
break
else: isNum = False
return num # at the end of the loop, it will return the number, no need for an else
Another way to do it:
def askFor(request):
"""Program asks for input, continues to ask until an integer is given"""
num, isNum = '', False
while not isNum:
num = raw_input(request)
try: # try to convert it to an integer, unless there is an error
num = int(num)
isNum = True
break
except ValueError:
isNum = False
return num
I am working with a Palindrome-detector that is built using for-loops (this was a requirement for the course I am attending).
I am almost fully done with it but I am having trouble returning an argument and using it in the final function. The code looks like this:
#-*- coding: utf-8 -*-
def main():
intro()
text = (input("Inser text here: "))
ordnaText(text)
testPalindrom(ordnaText(text))
showResult(testPalindrom)
def intro():
print ("Hej! Detta är ett program som testar ifall en text är ett palindrom eller inte.")
def ordnaText (text):
nytext = ("")
fixedText = text.lower()
for i in fixedText:
if i.isalnum():
nytext = (nytext + i)
return nytext
def testPalindrome(nytext):
palindrome = True
for i in range (0, len(nytext)):
if (nytext[i]) != (nytext[len(nytext)-i-1]):
palindrome = False
return palindrome
def showResult(palindrome):
if palindrome == True:
print ("Yes, this is a palindrome")
else:
print ("No, this is not a palindrome.)
main()
Everything works except the final part: if I put in "lol" which is a palindrome it says that it's false. "palindrome" somehow doesn't return correctly. What am I doing wrong?
For short strings, to test for palindromes just compare it against the reverse:
def testPalindrome(nytext):
return nytext == nytext[::-1]
Your version of testPalindrome works fine, but your method itself calls testPalindrom(ordnaText(text)) (no e at the end), so perhaps you have another definition of the function?
>>> def testPalindrome(nytext):
... palindrome = True
... for i in range (0, len(nytext)):
... if (nytext[i]) != (nytext[len(nytext)-i-1]):
... palindrome = False
... return palindrome
...
>>> testPalindrome('lol')
True
You don't actually pass the result of the function to showResult; you pass the function instead. Use a variable:
result = testPalindrome(ordnaText(text))
showResult(result)
You can simplify this down a little:
def testPalindrome(nytext):
for i in range (0, len(nytext)):
if (nytext[i]) != (nytext[len(nytext)-i-1]):
return False
return True
You can exit early when you find the first non-matching character.
You don't need to test for == True in if statements, just do:
def showResult(palindrome):
if palindrome:
print ("Yes, this is a palindrome")
else:
print ("No, this is not a palindrome.)
Your problem mainly lies in your main function:
ordnaText(text)
This calls the ordnaText function with the entered text as its parameter; and then it throws the result away.
testPalindrom(ordnaText(text))
Now this calls the testPalindrom function with the result from the ordnaText method; and then again it throws the result away. As you have already called the ordnaText method, it is also a good idea to store the result before, so you can just pass its result.
showResult(testPalindrom)
And finally, you call the showResult function with the function as a parameter. At this point, there is nothing that refers to the entered text, you just pass the function itself. So what you want to do here is pass the result of the testPalindrom function here:
text = input("Inser text here: ")
text = ordnaText(text)
testResult = testPalindrom(text)
showResult(testResult)
Try this (slightly cleaner code, same logic) :
def testPalindrome(str) :
for i in range(int(len(str)/2)) :
if str[i] != str[len(str)-i-1] :
return False
return True
Also, you arent doing anything with the result returned :
testPalindrom(ordnaText(text)) #This returns the result, but there is no variable that accepts it
showResult(testPalindrom)
You could do :
showResult(testPalindrom(ordnaText(text))) #This will print the returned result
Or :
result = testPalindrom(ordnaText(text))
showResult(result)
Advice : You can make this code much much shorter and tidier.
You have to pass the result of testPalindrom to showResult
By doing
ordnaText(text)
testPalindrom(ordnaText(text))
showResult(testPalindrom)
you pass the function itself to showResult (which is an object) which is not equal to True
so you should do instead of this three lines
showResult(testPalindrom(ordnaText(text)))