This question already has answers here:
How do "and" and "or" act with non-boolean values?
(8 answers)
Closed 3 years ago.
Saw this while searching and I couldn't understand the logic behind. How does and & or methods work in print()?
T=[int(s) for s in input().split()]
print(T and sorted(sorted(T,reverse=True),key=abs)[0] or 0)
I've tried simplifying it to understand how it handles different inputs.
print(A and B or C)
Returns B when B is not 0, and returns C when B is 0 but never gets to A.
This is an old style way to use ternary condition operator.
It has nothing related to print.
See this answer.
In most cases it does the same as this code
print(T and sorted(sorted(T,reverse=True),key=abs)[0] or 0)
print(sorted(sorted(T,reverse=True),key=abs)[0] if T else 0)
It works because of the way and and or works in Python - they do not return bool, but they return either first or second operand, depending if it casts to True or False.
This answer has more details.
Basically it's two operation
first = T and sorted(sorted(T,reverse=True),key=abs)[0]
and Return the first Falsy value if there are any, else return the last value in the expression.
So it either returns [] (possible Falsy value for T), or first element in sorted list.
result = first or 0
or Return the first Truthy value if there are any, else return the last value in the expression.
So if T is Truthy, we already have a Truthy value in first (unless it's 0, which is special case, but 0 or 0 is 0 anyway), it will be returned.
If T is [] - it will return 0.
As part of the answer, if given a non-empty list, T, of integers, the expression
sorted(sorted(T,reverse=True),key=abs)[0]
returns the integer in the list which is closest to zero. For example, if T = [3, -2, 4, 5], it will return -2.
The subtle point is what is does in a case like T = [3, -2, 4, 2] where -2 and 2 are tied in being closest. In this case it will return 2 rather than -2. The logic for this particular case is that sorted(T, reverse = True) will put all of the positive numbers before any of the negative numbers, so that 2 will be before -2. When the result of that sort is then sorted again with key = abs, the 2 and -2 are already in sorted order (relative to key = abs), so they won't be swapped, hence 2 rather than -2 will be the first element of the list. The code is actually somewhat subtle and depends on the fact that Timsort is a stable sorting algorithm.
Related
while [List]: vs while [List] is True? What is the different?
For example I am doing this problem (heap and priority queues) https://leetcode.com/problems/find-k-pairs-with-smallest-sums/ and here is a sample solution that I retrieved. I do not understand this line while len(res) < k and heap:. Why do I need while heap:? and Also when I tried while ... heap is True, the code no longer works.
class Solution:
"""Returns List[List[int]]"""
def kSmallestPairs(self, nums1, nums2, k):
# nums1 and nums2 are both sorted list
res = []
if not nums1 or not nums2 or not k:
return res
heap = []
visited = set()
heapq.heappush(heap, (nums1[0] + nums2[0], 0, 0))
visited.add((0, 0))
while len(res) < k and heap:
_, i, j = heapq.heappop(heap)
res.append([nums1[i], nums2[j]])
if i + 1 < len(nums1) and (i + 1, j) not in visited:
heapq.heappush(heap, (nums1[i + 1] + nums2[j], i + 1, j))
visited.add((i + 1, j))
if j + 1 < len(nums2) and (i, j + 1) not in visited:
heapq.heappush(heap, (nums1[i] + nums2[j + 1], i, j + 1))
visited.add((i, j + 1))
return res
There are a few different things necessary to fully understand the topic you're asking about.
The first is what do the is operator does. It checks for identity, that is, if A is B is true, then A and B must be two references to the same object.
The second is boolean contexts. When you use an expression in a if or while statement's condition, or pass it as the first argument to the and or or operators (or the only argument to the unary not operator), Python will implicitly convert your object into a bool value before considering if the condition is passed or not. Different types may handle this conversion differently, by implementing whatever logic they want in their __bool__ method. For the builtin types, bool(o) is False only for numerical values that are equal to zero, and for container objects that are empty (and None is always falsey). All other values are truthy (as are instances of user-created classes, by default).
Note the terminology I'm using here. When dealing with boolean contexts, we often talk about "truthiness" rather than something being true or false. An object o is "truthy" if bool(o) is True, and "falsey" if bool(o) is False. A truthy value isn't generally equal to True. And while a bunch of numerical falsey values are equal to False (because False is equal to zero), other kinds of falsey values (like empty strings and empty lists) are not equal to either zero or False.
In the code you're asking about, a list named heap is tested in a boolean context. That means the condition will be true (and the while loop will keep going) if the list is non-empty. You can see why that's important by looking at the very first line of the loop body, where heapq.heappop is called on the list. That function will raise an exception if heap is empty, so the code stops the loop if that's the case.
Testing heap is False is not remotely equivalent, because heap is a list, and so it will never be a reference to the same object as the False literal. In some situations it might make sense for a loop condition to use is, but this is definitely not one of those situations.
Writing bool(heap) is True could make some amount of sense, but it's unnecessary, since just heap (in the context of a while loop's condition) works just as well.
If you want to be more explicit about the check, you could test the length of the list directly, with len(heap) > 0. This is also longer than just using heap by itself, but it might be worth writing anyway if you feel it is more expressive of the meaning you intend (though experienced Python programmers will understand what heap means in a boolean context).
(I'd further note that your question was a bit more confusing than it needed to be because you're using [List] as a sort of pseudocode meaning "some kind of list", despite the fact that that string is valid Python syntax. Without your textual explanation, I'd expect [List] to mean a one-element list containing a value named List, which would always be truthy, since it's not empty. Avoiding ambiguous notation in your questions will help you get quicker and better answers to your questions.)
any data can be True or False
remember this:
0 -> False (but be care '0' as string is True, because it's a string that not equal to '' empty one)
'' -> False (empty string = False)
[] -> False (empty list, empty tuple, empty set, empty dict = False)
[] - this is False
['something'] - this is True
so when you see things like this: if [list] or while [list]
you should see them like:
if [this list is not empty]
while [this list is not empty == while it's True]
so this while len(res) < k and heap means:
while length of res < k and heap is True (-> not empty, not 0, not False)
Question that asks:
"Create a function that returns the characters from a list or string r
on odd or even positions, depending on the specifier s. The specifier
will be "odd" for items on odd positions (1, 3, 5, ...) and "even" for
items on even positions (2, 4, 6, ...)."
E.g. char_at_pos([2, 4, 6, 8, 10], "even") ➞ [4, 8]
Have managed to solve, but saw a quicker way to solve would be to use:
def char_at_pos(r, s):
return r[s == 'even'::2]
am wondering how to interpret r[s == 'even'::2], is that adding a condition inside the index bracket before we pick the even index numbers in the list? How does it then also pick the odd numbers?
r[s == 'even'::2]
s == 'even' evaluates to 1 (which is the numerical equivalent for True) if s is 'even', otherwise it evaluates to zero (which is the numerical equivalent for False). Now lets break it down based on examples:
r[1:10] takes all items startig at 1 till item 10 (excluded).
r[1:] takes all items starting at 1 till the end.
r[1:10:2] takes every second item starting at 1 till item 10, and
r[1::2] correspondingly takes every second item starting at 1 till the end.
Adding to the #jim answer,
Booleans in Python are implemented as a subclass of integers.
>>> int(True)
1
>>> int(False)
0
>>> issubclass(type(True), int)
True
>>> issubclass(type(False), int)
True
When you call r[s == 'even'::2] python calls the __getitem__ method of the list object with the slice object slice(True, None, None) or slice(False, None, None)[Depends upon the result of s == 'even']. The PySlice_Unpack C API call will extract the start, stop, step data members from a slice object as C integers. So this is where the start(boolean object) argument is actually is converting to an int object making the expression to be evaluated as same as r[1::2] or r[0::2]
Learning programming in Python and I am doing some challenges. I've run into something I haven't learned yet and was curious what this code is doing.
So my challenge is called the "FizzBuzz" challenge. The instructions are simple:
Create a function that takes a number as an argument and returns
"Fizz", "Buzz" or "FizzBuzz".
If the number is a multiple of 3 the output should be "Fizz". If the
number given is a multiple of 5, the output should be "Buzz". If the
number given is a multiple of both 3 and 5, the output should be
"FizzBuzz". If the number is not a multiple of either 3 or 5, the
number should be output on its own.
I wrote this code to solve it (obviously it can be better):
def fizz_buzz(num):
if num % 3 == 0 and num % 5 == 0:
return 'FizzBuzz'
elif num % 3 == 0:
return 'Fizz'
elif num % 5 == 0:
return 'Buzz'
else:
return str(num)
But, once I submitted my solution I was able to see the top solution, which is:
def fizz_buzz(num):
return "Fizz"*(num%3==0) + "Buzz"*(num%5==0) or str(num)
My question is what is the * doing here? Can someone point me to documentation or resources that addresses what this persons code has done? I don't find it super readable but it is apparently the best solution to the problem.
bool in Python is a subclass of int; True has the value 1, False, 0.
Sequences (including str) in Python can be multiplied, to get the sequence repeated that many times, so:
"Fizz"*(num%3==0)
multiplies "Fizz" by 1 (numeric value of True) when num % 3 == 0, producing the original string, and by 0 (numeric value of False) otherwise, producing the empty string.
The same work is done with "Buzz" and concatenated. If both of them produced the empty string (which is falsy), then the or means str(num) is evaluated and returned (Python's or and and don't evaluate to strict True or False, they evaluate to the last item evaluated, and short-circuit, so or always evaluates to the first truthy item, or the last item in the or chain regardless of truthiness).
Firstly, shorter doesn't always mean better. In this case, your solution is fine, and the "top solution" is clever, but needlessly confusing, as you're aware :P
The star is doing string multiplication, and it's exploiting the fact that False == 0 and True == 1. So if num is divisible by 3, you get 'Fizz' once, and if num is divisible by 5, you get 'Buzz' once. Otherwise you get an empty string, '', and because an empty string is falsy, the or clause means it will be replaced by str(num).
The * is string multiplication as usual. It's just multiplying by 0 or 1 based on whether the condition to print the phrase is met. If neither condition is met, it defaults to returning the number, as it should.
I don't know about a resource, but I can tell you what it does. The phrase num%3==0 is a Boolean which is true if the number is divisible by 3. If that's the case, this phrase returns a 1 (or 0 if False). Same for num%5==0 and divisible by 5. This is then being multiplied by the string Fizz and/or Buzz and concatenated together, where multiplying by 1 returns the string and 0 nothing. If neither of those holds, it returns str(num).
I do not know the link to any documentation or resource about it, but I can explain it to you.
Firstly in python str can be multiplied by a number, for instance 'Fizz' * 3 will return 'FizzFizzFizz' or 'Fizz' * 0 will return '', an empty string.
Secondly bool in python can be also recognized as int, i.e. True is 1 and False is 0.
Thirdly in python strings can be added e.g. 'Fizz'+'Buzz' will return 'FizzBuzz'
What the best solution guy does is very simple by num%3==0 he gets bool and just multiplies the str 'Fizz' or 'Buzz' by it and returns.
I am learning the recursive functions. I completed an exercise, but in a different way than proposed.
"Write a recursive function which takes a list argument and returns the sum of its integers."
L = [0, 1, 2, 3, 4] # The sum of elements will be 10
My solution is:
def list_sum(aList):
count = len(aList)
if count == 0:
return 0
count -= 1
return aList[0] + list_sum(aList[1:])
The proposed solution is:
def proposed_sum(aList):
if not aList:
return 0
return aList[0] + proposed_sum(aList[1:])
My solution is very clear in how it works.
The proposed solution is shorter, but it is not clear for me why does the function work. How does if not aList even happen? I mean, how would the rest of the code fulfill a not aList, if not aList means it checks for True/False, but how is it True/False here?
I understand that return 0 causes the recursion to stop.
As a side note, executing without if not aList throws IndexError: list index out of range.
Also, timeit-1million says my function is slower. It takes 3.32 seconds while the proposed takes 2.26. Which means I gotta understand the proposed solution.
On the call of the function, aList will have no elements. Or in other words, the only element it has is null. A list is like a string or array. When you create a variable you reserve some space in the memory for it. Lists and such have a null on the very last position which marks the end so nothing can be stored after that point. You keep cutting the first element in the list, so the only thing left is the null. When you reach it you know you're done.
If you don't use that condition the function will try to take a number that doesn't exist, so it throws that error.
You are counting the items in the list, and the proposed one check if it's empty with if not aList this is equals to len(aList) == 0, so both of you use the same logic.
But, you're doing count -= 1, this has no sense since when you use recursion, you pass the list quiting one element, so here you lose some time.
According to PEP 8, this is the proper way:
• For sequences, (strings, lists, tuples), use the fact that empty
sequences are false.
Yes: if not seq:
if seq:
No: if len(seq)
if not len(seq)
Here is my amateur thougts about why:
This implicit check will be faster than calling len, since len is a function to get the length of a collection, it works by calling an object's __len__ method. This will find up there is no item to check __len__.
So both will find up there is no item there, but one does it directly.
not aList
return True if there is no elements in aList. That if statement in the solution covers edge case and checks if input parameter is not empty list.
For understand this function, let's run it step by step :
step 0 :
L=[0,1,2,3,4]
proposed_sum([0,1,2,3,4])
L != []
return l[0] + proposed_sum([1,2,3,4])
step 1 calcul proposed_sum([1,2,3,4]):
proposed_sum([1,2,3,4])
L != []
return l[0] + sum([2,3,4])
step 2 calcul proposed_sum([2,3,4]):
proposed_sum([2,3,4])
L != []
return l[0] + sum([3,4])
step 3 calcul proposed_sum([3,4]):
proposed_sum([3,4])
L != []
return l[0] + sum([4])
step 4 calcul proposed_sum([4]):
proposed_sum([4])
L != []
return l[0] + sum([])
step 5 calcul proposed_sum([]):
proposed_sum([])
L == []
return 0
step 6 replace:
proposed_sum([0,1,2,3,4])
By
proposed_sum([]) + proposed_sum([4]) + proposed_sum([3,4]) + proposed_sum([2,3,4]) + proposed_sum([1,2,3,4])+ proposed_sum([0,1,2,3,4])
=
(0) + 4 + 3 + 2 + 1 + 0
Python considers as False multiple values:
False (of course)
0
None
empty collections (dictionaries, lists, tuples)
empty strings ('', "", '''''', """""", r'', u"", etc...)
any other object whose __nonzero__ method returns False
in your case, the list is evaluated as a boolean. If it is empty, it is considered as False, else it is considered as True. This is just a shorter way to write if len(aList) == 0:
in addition, concerning your new question in the comments, consider the last line of your function:
return aList[0] + proposed_sum(aList[1:])
This line call a new "instance" of the function but with a subset of the original list (the original list minus the first element). At each recursion, the list passed in argument looses an element and after a certain amount of recursions, the passed list is empty.
I am currently new to Python and am trying to run a few simple lines of code. I cannot understand how Python is evaluating this syntax after the if statement. Any explanations will be appreciated.
number = int(raw_input("Enter number : "))
if number == (1 or 2 or 3):
print "Match"
else:
print "No match"
Only the integer 1 yield a positive result and any other numbers including 2 and 3 go through the else branch. Can the conditions be stated as the following only?:
if number == 1 or number == 2 or number == 3:
Thank you.
You probably want:
if number in (1, 2, 3):
Python has boolean values, such as True and False, and it also has falsy values, such as any empty list, tuple, or dictionary, an empty string, 0, and None. Truthy values are the opposite of that, namely anything that's defined.
Python's or evaluates and short-circuts on the first element that returns a truthy value.
So, the expression (1 or 2 or 3) is going to return 1.
If you want to compare against all elements, then you're looking for the in keyword:
if number in (1, 2, 3):
# Do logic
The or operator takes two arguments, on its left and right sides, and performs the following logic:
Evaluate the stuff on the left-hand side.
If it is a truthy value (e.g, bool(x) is True, so it's not zero, an empty string, or None), return it and stop.
Otherwise, evaluate the stuff on the right-hand side and return that.
As such, 1 or 2 or 3 is simply 1, so your expression turns into:
if number == (1):
If you actually mean number == 1 or number == 2 or number == 3, or number in (1, 2, 3), you'll need to say that.
(Incidentally: The and operator works the same way, except step 2 returns if the left-hand-side is falsey.)