Trying to understand "or" operator inside lambda [duplicate] - python

This question already has answers here:
How do "and" and "or" act with non-boolean values?
(8 answers)
Closed 4 months ago.
I came across following code while solving this problem:
f=lambda n:"a"[n:]or f(n-1)+chr(97+n)+f(n-1)
The function generates abacaba sequence of specific depth n
For example:
n = 2, output: 'abacaba'
n = 3, output: 'abacabadabacaba'
The question is, how does the code work? Namely, how does "or" operator work inside lambda? (I assume code above uses recursion, and to my knowledge, normally we use loops for recursion, but I don't see anything that resembles loops in the code above)

It works the same way it does anywhere else. If the left-hand argument of or is truthy, the expression evaluates to that; otherwise, it evaluates to the right-hand argument. In this case, "a"[n:] is the empty string when n > 0, so it's equivalent to
def f(n):
if n == 0:
return "a"
else:
return f(n-1) + chr(97+n) + f(n-1)

Let's break it down.
f = lambda # declare a variable f that is a function
n: # that takes an int parameter 'n'
"a"[n:] # if n is 0 return 'a'
or # else
f(n-1) # return a recursive call at n - 1
+ # plus
chr(97+n) # character from code 97 + n
+ # plus
f(n-1) # another recursive call

Related

Python react differently based on how I declare loop conditions [duplicate]

This question already has answers here:
Python boolean evaluation order
(2 answers)
Does Python support short-circuiting?
(3 answers)
Closed 2 years ago.
please see comments, two different while loop conditions have different outcomes, is this because of and operator? I couldn't figure out why.
def longestPalindrome(s: str) -> str:
output = ""
for i in range(len(s)):
temp = check(s,i,i)
if len(output) < len(temp):
output = temp
temp = check(s,i,i+1)
if len(output) < len(temp):
output = temp
return output
def check(s: str, l: int, r: int) -> str:
while (l >= 0 and r < len(s) and s[l] == s[r]):
# while (s[l] == s[r] and l >= 0 and r < len(s)):
# above will result in 'string index out of range' error which I couldnt figure out why
l-=1;r+=1
return s[l+1:r]
print(longestPalindrome("adaa")) # this will return "ada"
Your while statement checks left to right. So when it goes to s[l] == s[r], if any of the index value is out of range, it will error out. By checking for l and r first, you are exiting before it reaches the s[l] == s[r] condition
This is because the and operator is a short-circuit operator. This means that the second argument of the and operator is only evaluated if the first one is true.
In your case, at some point during the loop, r is equal to the length of s, so s[r] doesn't exist. The first while loop works because r < len(s) is false and thus short-circuits the last part of the condition.
In the second loop, Python, tries to evaluate s[l] == s[r] first. As s[r] doesn't exist, an IndexError is raised.
You can check out the documentation here

Python Function Won't Return Value [duplicate]

This question already has an answer here:
Why Python recursive function returns None [duplicate]
(1 answer)
Closed 2 years ago.
I'm trying to create a recursive function in Python (as part of an online course) which takes two numbers and returns the highest common denominator between them, however, the function won't return the value.
My code is:
def gcdRecur(a, b):
x = min(a,b)
y = max(a, b)
if x == 0:
return y
else:
gcdRecur(x, y%x)
When I test the function with
gcdRecur(2,12)
or
gcdRecur(6,12)
nothing is returned. I know the function works because if I print y before I return it then the correct denominator is printed to the console, I'm just not sure why the function doesn't output y.
It's probably something obvious but as I'm new to Python I'm not sure what I'm doing wrong.
Any help would be much appreciated.
You need to return something in both branches:
else:
return gcdRecur(x, y%x)

Python - Recursive Function Without Return Logic [duplicate]

This question already has answers here:
Why does my recursive function return None?
(4 answers)
Closed 4 years ago.
I had trouble understanding why this function returns None:
def rem(x, a):
"""
x: a non-negative integer argument
a: a positive integer argument
returns: integer, the remainder when x is divided by a.
"""
if x == a:
return 0
elif x < a:
return x
else:
rem(x-a, a)
rem(7, 5)
I then realized that the last line in the function should be:
return rem(x-a, a)
I am still unsure as to what really happens in the first one. It looks like there are 2 seperate function calls, one returning 2 and the other None... any help?
All python function returns None if it doesn't terminate by a return statement. In your case, you successfully called the recursion but you discarded the result in the else part. And after the if-block, the default return None is implicitly executed.

Can someone tell me why this while loop works in python? [duplicate]

This question already has answers here:
What is Truthy and Falsy? How is it different from True and False?
(8 answers)
Closed 5 years ago.
sum, Nr = 0, 12
i = Nr
while i:
sum += i
i -= 1
print ('The sum of all natural numbers up to (and inclusive of) ' + repr(Nr) +
' is ' + repr(sum))
So this is a very simple while loop in python 3 which returns "The sum of all natural numbers up to (and inclusive of) 12 is 78" as expected.
What I am confused about is that why this condition "while i:" works here when "i" is not subjected to any comparison operator.
Thanks!
In conditional statements, the input is implicitly cast to boolean, hence the loop is equivalent to
while bool(i):
...
bool(i) is True as long as i != 0, and False if i == 0, so the loop goes until i becomes zero.
While expect the expression and if it is true is runs the loop.
while_stmt ::= "while" expression ":" suite
["else" ":" suite]
In [38]: bool(Nr)
Out[38]: True
while loop expects any condition either True or False. When you write while i (suppose i = 5) it is evaluated as True, so the loop continues but when it encounters i=0 it is evaluated as False and the loop breaks.
It seems that Python does an implicit replacement with i not equals zero (pseudo code). See documentation.
Python automatically computes the truthy value of the variable passed to it by converting it into boolean. Since i being a non-zero positive integer is considered true in Python, that's why it's working, till it finally becomes 0 which is considered false.
>>> print(bool(3))
True
>>> print(bool(0))
False
In python, values are duck typed - what this means is that the interpreter can try to fit the value into whatever context you have put it. All numbers other than zero are 'truthy', so for instance
if 3: # True
Whereas zero is falsy:
if 0: # False

Using IF, AND, OR together with EQUAL operand together in Python [duplicate]

This question already has answers here:
How to test multiple variables for equality against a single value?
(31 answers)
Closed 6 years ago.
I'm trying to create a function where the given value (passed as a string) is checked to see if the number of digits is either 4 or 6, and that it is a number.
My first impulse was to go with this code:
def number(x):
if (len(x) == (4 or 6)) and x.isdigit():
print "True"
else:
print "False"
This code above only passes the first test below...I don't understand why it passes this but none of the other tests:
number("1234")
Only when I separate out the len() functions will it work properly.
def number(x):
if (len(x) == 4 or len(x) == 6) and x.isdigit():
print "True"
else:
print "False"
## Checks
number("1234")
number("123456")
number("abcd")
number("abcdef")
number("1")
number("a")
The above code passes all tests.
So my questions are:
What's going on here?
Any way to write cleaner code for this?
Thank for the help!
** Not a duplicate question because although this question has the same underlying concepts regarding boolean operators, the problem itself is different due to the usage of len(), isdigit(), and the additional question of how best to improve it (someone commented the usage of return). Definitely adds another perspective to the other question though.
It helps to examine the logic of this line:
if (len(x) == (4 or 6)):
The (4 or 6) clause contains a logical or short circuit. The value 4 is true, so it is evaluated and returned to the == relational comparison.
The way that or works is that its lefthand side is evaluated for Boolean truth, and its value is returned if true. If the lefthand side is not Boolean true, then the righthand side is evaluated and its value is returned.
Because the lefthand side of the 4 or ... is true in a Boolean sense, the righthand side is never evaluated. Python doesn't even look past 4 or. If the left-hand value were a false value (such as 0), then the right hand side of the or would be evaluated.
To see this in action, try print 4 or 6. The output will be 4.
So since the 4 is a hard-coded true value, your comparison is semantically the same as if (len(x) == 4) -- that is, since 4 is true, 6 is never evaluated.
What I suppose you really want to know is if len(x) is either 4 or 6. You could put that to code in a couple of ways:
if(len(x) == 4 or len(x) == 6 ...
if(len(x) in (4,6) ...
You can use the in operator like so:
def number(x):
if len(x) in (4, 6) and x.isdigit():
print "True"
else:
print "False"
where in checks for containment in a given container. Note that 4 or 6 on their own evaluate to something undesirable, which is why your first code segment fails. You can check it out on the python shell:
>>> 4 or 6
4
You probably wanted to write
if (len(x) in (4, 6)) and x.isdigit():
Instead of
if (len(x) == (4 or 6)) and x.isdigit():
Short answer: len(x) in [4, 6] or len(x) == 4 or len(x) == 6.
"or" is a boolean, or logical choice. (4 or 6) is guaranteed to resolve to a non-zero (true) value. In this case, it resolves to 4, so your test case passes.
I'll go ahead and answer
Any way to write cleaner code for this?
Yes. Return the boolean value, rather than printing a string.
def number(x):
return len(x) in {4, 6} and x.isdigit()
print(number("1234")) # True
Then, it is simple do use your method in a if-statement without string comparison.
The trouble is in your or statement.
Any value greater than one will evaluate to True when you put it in a conditional. So (4 or 6) will always resolve to true.
You could use the in statement above or you could just use two =='s:
if (len(x) == 4 or len(x) == 6) and x.isdigit()
It's a bit wordier, I find it easier to read.

Categories

Resources