Could someone explain this code for me? - python

Can someone explain this piece of code for me, in simple terms.
prompts = ("Enter Strength Attribute, between 1 and 50: ", "Enter Skill Attribute, between 1 and 50: ") # I already now this so no need to explain it
answers = [int(input(p)) for p in prompts]
if not all(0 < a <=50 for a in answers):
# other code here
Is it a generator?
And how does it work?
Thanks in advance for any answers.

You have a list comprehension and a generator expression.
The list comprehension is:
[int(input(p)) for p in prompts]
and produces a list of integers from a list of prompts, asking the user for a series of numeric values.
It could also be expressed as:
answers = []
for p in prompts:
result = int(input(p))
answers.append(result)
Next is:
(0 < a <=50 for a in answers)
which is the generator expression. It tests if each of the numbers is a value between 0 (exclusive) and 50 (inclusive).
The all() function will loop over the generator expression one result at a time, and will return False the moment one of those results is False, or True when it exhausts the generator results and no False values were found.
You could replace the if all(...) test with:
result = True
for a in answers:
if not 0 < a <= 50:
result = False
break
if result:
This would achieve the same effect; loop over answers one by one, but stop looping early if any of the tests was False (not a number greater than 0 and smaller than or equal to 50).

answers = [int(input(p)) for p in prompts]
This is a list comprehension. It could be written as a for loop like this:
answers = []
for p in prompts:
resp = int(input(p))
answers.append(resp)
if not all(0 < a <=50 for a in answers):
This is a generator, wrapped in all (a built in function that returns whether all elements are true) You could write that as a function:
def all(answers):
for a in answer:
if not 0 < a <= 50:
return False # note this short-circuits, stopping the loop
return True

It is a list comprehension.
The first line does exactly the same as:
answers=[]
for p in prompts:
a=int(input(p))
answers.append(a)
The part of the second line behind the if condition does exactly the same as:
for a in answers:
if a <= 0 or a > 50:
return False
return True

for p in prompts
enumerates the prompts
int(input(p))
asks the user for an input, using the p as a prompt, then try to coerce the input as an int
answers = [...]
makes answers a list of all the inputs converted in ints (this is a comprehension list)
(0 < a <=50 for a in answers)
This is a generator. It creates an iterable containing the test 0 < a <=50 for each value in the answers list
if not all(...)
Tests all elements in the generator. if any one is false, do other code

Related

Order of appearance for if/else in list comprehension based on for loop [duplicate]

This question already has answers here:
Is it possible to use 'else' in a list comprehension? [duplicate]
(6 answers)
Closed 2 years ago.
Learning list comprehensions and discovered that if/if-else statement can be placed in different order of apperance in expression.
In example, starting understanding list comprehension construction from for loop schema:
positive = []
for number in numbers:
if int(number) >= 0:
positive.append(int(number))
else:
positive.append(0 - int(number))
can be evaluated to:
positive = [int(number) if int(number) >= 0 else 0 - int(number) for number in numbers]
But
positive = []
for number in number:
if int(number) >= 0:
positive.append(int(number))
goes to:
positive = [int(number) for number in numbers if int(number) >= 0]
I know that one of useful technique for creating list comprehension is to read for loop from top to down and put them in one line (a little shortcut of course).
But why those 2 examples put if / if-else statement once in front and secondly in the end of construction?
In the first case, you're choosing between two options; but in either choice, you're adding to the list. Whatever comes before the for is added to the list.
In the second case, you're only adding to the result list in one option. Whatever comes after the for construct on the right decides if something is added at all.
If you want to pick what's added between (usually two) options, use the first. If you what to pick if something is added at all, use the second.

If variables are not in given range, return error message - but error message always returned?

I've been racking my brain trying to figure out why this easy program does not work. It always returns the error message.
It's a program that takes 5 integers and adds them up, however if they are above 100 or less than 0, it returns an error message.. except it always returns this no matter what numbers are put in.
I'm new, so I know it's perhaps over complicated or roundabout, but it should work anyways.This is a picture of my programming.
or doesn't work the way you think it does.
It compares the two statements next to it and if one of them is True then the statement is correct. In this case, all integers are true so with the first or statement:
int_one or int_two...
will always be true because integers are considered as True! Your comparison should thus be:
if int_one not in range or int_two not in range or int_three not in range or int_four not in range or int_five not in range:
To make this comparison faster, I would make a list and use while to make the user input their input into the list and compare them one by one:
user_input_list = []
i = 0
while len(user_input_list) < 5:
user_input = int(input("Enter the " + str(i+1) + "th number:"))
if 0 <= user_input <= 100:
user_input_list.append(user_input)
i += 1
else:
print("Please enter a number from 0 to 100")
Try it here!
In the future post your code in your question using the code format options.
the "or" operator looks at the output of 2 expressions that return boolean true/false values. So the way you use it is incorrect.
>>> if 1 or 2 or 3 not in [1,2,3]:
... print "hi"
...
hi
>>> if 1 not in [1,2,3] or 2 not in [1,2,3] or 3 not in [1,2,3]:
... print "hi"
...
>>>
Consider the above examples. The first one is what you are doing. You should be doing the latter.

how to find number that's divisible by a number in a given range?

I have this code:
generateMin = 150
generateMax = 250
if (current_level.world_shift * -1 % n == 0
for n in range(generateMin, generateMax)):
print("in range")
Which is checked at 100 FPS — as I move right/left current_level.world_shift is changed. However this code does not work. Can someone help me with that?
You can't use a generator expression in an if statement like that. This is because initially a generator expression yields a new generator object and instances of most types are generally considered True (see Truth Value Testing in the documentation).
To do what you want I suggest you instead use the built-in any() function. Doing so will be fast because it will stop soon as a True boolean sub-expression value is encountered.
Here's what I mean:
# a couple of things to allow dot syntax used in question to be used in answer
class Level: pass
current_level = Level()
current_level.world_shift = -175
generateMin = 150
generateMax = 250
if any(current_level.world_shift*-1 % n == 0
for n in range(generateMin, generateMax)):
print("in range")
any() will return True if current_level.world_shift*-1 is evenly divisible by any number in the open-ended range (assuming that's what you're trying to determine). By open-ended I mean that the value generateMax will not be considered because range(start, stop) only covers the values from start to stop-1.
I think you're misunderstanding the range() method. It doesn't create a random number, it creates a list of numbers in a particular range. E.g., range(1,5) yields [1,2,3,4]
import random
generateMin = 150
generateMax = 250
if (current_level.world_shift * -1 % random.randint(generateMin, generateMax) == 0):
print("in range")
I think you were trying to have an assignment in the conditional, e.g., if (n == 1 with n = 1), but mistakenly ended up using list comprehension, which always validated as True. I'm kind of amazed that didn't give a syntax error.
Python does not support assignment within a conditional, you'll need to assign before the if, or don't assign at all, like in the above code.

Recursively return a tuple of numbers 0 to n in python [duplicate]

This question already has answers here:
Python Recursion: Range
(5 answers)
Closed 7 years ago.
So what I'm trying to do is basically make a recursive function that returns a tuple of numbers from 0 to a given number n that does not use range(), loops or lists. The problem reads as this:
"Define a recursive function called rec_range() that takes a natural number n and returns a tuple of numbers starting with 0 and ending before n. So rec_range(5) returns (0,1,2,3,4) and rec_range(1) returns (0,)."
The problem is that I have no idea how to make a function that returns a tuple. I know how to get a factorial of a number n using recursion, but we never went over how to return multiple numbers in a tuple.
The only thing I have right now is this:
def rec_range(n):
"""Takes a natural number n and returns a tuple of numbers starting with 0 and ending before n.
Natural Number -> tuple"""
if n == 0
return (,)
elif n == 1:
return (0,)
else:
???
Sorry if the answer to this is actually really obvious I'm very new to programming
You want to append tuples together, so use + and recurse over your function lowering the value by 1 . In addition, just return (or return None) for n == 0. Really the n == 0 call is unnecessary and your code could be more idiomatic, but I'll leave that to you.
def rec_range(n):
"""Takes a natural number n and returns a tuple of numbers starting with 0 and ending before n.
Natural Number -> tuple"""
if n == 0:
return
elif n == 1:
return (0,)
else:
return rec_range(n-1) + (n-1,)
Outputs:
>>>rec_range(4)
(0, 1, 2, 3)

How can I use recursion to find palindromes using Python?

I've just started exploring the wonders of programming. I'm trying to write a code to identify numeric palindromes. Just looking at numbers and not texts. I'm trying to learn to use recursion here. But I'm just not getting anywhere and I can't figure out what's wrong with it.
My idea was to check first string vs the last, then delete these two if they match, and repeat. Eventually there'll be nothing left (implying it is a palindrome) or there will be a couple that doesn't match (implying the reverse).
I know there are better codes to finding palindromes in but I just wanted to try my hand at recursion.
So what's wrong?
def f(n):
global li
li=list(str(n))
if (len(li)==(1 or 0)):
return True
elif li[len(li)-1]==li[0]:
del li[0]
del li[len(li)-1]
if len(li)==0:
return True
if len(li)>0:
global x
x=''.join(li)
str(x)
f(x)
else:
return False
Thanks in advance!
A few comments
Why are x and li globals? In recursion, all variables should be local.
Why are you converting back and forth between str and list? You can subscript both of them
You need to return the result of your recursive call: return f(x)
Try these suggestions, and see how it works out.
Before looking into it too much, if (len(li)==(1 or 0)): doesn't do what you're expecting it to do. (1 or 0) will always evaluate to 1.
You probably want:
if len(li) in (1, 0):
There are a couple of problems with your solution. Let me analyse them line by line.
You don't need global statements if you don't intend to change variables outside of function scope. Thus, I removed two lines with global from your code.
li=list(str(n)): casting a string to a list is unnecessary, as a string in Python has a similar interface to an immutable list. So a simple li = str(n) will suffice.
if (len(li)==(1 or 0)):: although it looks OK, it is in fact an incorrect way to compare a value to a few other values. The or operator returns the first "true" value from its left or right operand, so in this case it always returns 1. Instead, you can use the in operator, which checks whether the left operand is an element of a right operand. If we make the right operand a tuple (1, 0), all will be well. Furthermore, you don't need parentheses around the if statement. You should write: if len(li) in (1, 0):
elif li[len(li)-1]==li[0]: is fine, but we can write this shorter in Python, because it supports negative list indexing: elif li[-1] == li[0]:
Because we don't use lists (mutable sequences) because of point 2., we can't do del li[0] on them. And anyway, removing the first element of a list is very inefficient in Python (the whole list must be copied). From the very same reason, we can't do del li[len(li)-1]. Instead, we can use the "splicing" operator to extract a substring from the string: li = li[1:-1]
if len(li)==0: is unnecessary long. In Python, empty strings and lists resolve to False if tested by an if. So you can write if not li:
if len(li)>0:: You don't have to check again if li is not empty -- you checked it in point 6. So a simple else: would suffice. Or even better, remove this line completely and unindent the rest of the function, because the body of the if in 6. contains a return. So if we didn't enter the if, we are in the else without writing it at all.
x=''.join(li): We don't need to convert our string to a string, because of the decision made in 2. Remove this line.
str(x): This line didn't do anything useful in your code, because str() doesn't modify its argument in place, but returns a new value (so x = str(x) would have more sense). You can also remove it.
f(x): This is a valid way to call a recursive function in Python, but you have to do something with its value. Return it perhaps? We'll change it to: return f(li) (as we don't have an x variable any more).
We end up with the following code:
def f(n):
li = str(n)
if len(li) in (1, 0):
return True
elif li[-1] == li[0]:
li = li[1:-1]
if not li:
return True
return f(li)
else:
return False
It's almost what we need, but still a little refinement can be made. If you look at the lines if not li: return True, you'll see that they are not necessary. If we remove them, then f will be called with an empty string as the argument, len(li) will equal 0 and True will be returned anyway. So we'll go ahead and remove these lines:
def f(n):
li = str(n)
if len(li) in (1, 0):
return True
elif li[-1] == li[0]:
li = li[1:-1]
return f(li)
else:
return False
And that's it! Good luck on your way to becoming a successful programmer!
Split the whole show out into a list, then just:
def fun(yourList):
if yourList.pop(0) == yourList.pop(-1):
if len(yourList) < 2:
return True # We're a palindrome
else:
return fun(yourList)
else:
return False # We're not a palindrome
print "1234321"
print fun(list("1234321")) # True
print "6234321"
print fun(list("6234321")) # False
def palindrome(n):
return n == n[::-1]
It's hard to tell what you intend to do from your code, but I wrote a simpler (also recursive) example that might make it easier for you to understand:
def is_palindrome(num):
s = str(num)
if s[0] != s[-1]:
return False
elif not s[1:-1]:
return True
else:
return is_palindrome(int(s[1:-1]))
number = int(raw_input("Enter a number: "))
rev = 0
neg = number
original = number
if (number < 0):
number = number * -1
else:
number = number
while ( number > 0 ):
k = number % 10
number = number / 10
rev = k + ( rev * 10 )
if (number < 1):
break
if ( neg < 0 ):
rev = ( rev * -1)
else:
rev = (rev)
if ( rev == original):
print "The number you entered is a palindrome number"
else:
print "The number you entered is not a palindrome number"
This code even works for the negative numbers i am new to programming in case of any errors
dont mind.

Categories

Resources