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.
Related
This question already has answers here:
What is Truthy and Falsy? How is it different from True and False?
(8 answers)
Closed 2 years ago.
Okay, so here is a piece of code. The function of the code is to take a value and determine whether or not it is odd or even.
def isEvenOrOdd(num):
return 'odd' if num % 2 else 'even'
Now my question lies in why this works. The way I am currently looking at this, is that --
num%2 returns a value. If num is 3, then num%2 = 1.
Why would the value of '1' satisfy the 'if' condition?
I assumed this was a matter of 1 and 0, but I tried the same code with %4, and if 3 is returned, it still satisfies the if statement.
I understand this may be a basic question for some, so my apologies for perhaps being slow in understanding this. Thank you!
Thank you for your help ! I actually understand it now
The reason has to do with the "truthy-ness" of objects in Python. Every object in Python, even if it's not a boolean value, is considered "truthy" or "falsy". In this case, an integer is considered "truthy" if and only if it is not zero.
Therefore, if the number is odd, its modulus will be 1 which is considered true. Otherwise, the modulus will be 0 which is considered false.
If you switch the modulus to 4, the result will be truthy iff the remainder is not zero (i.e., if the number isn't a multiple of 4).
in python the, some data types has a true value or a false value, it doesn't have to be a boolean.
for example
test = None
if test:
print("working")
else:
print("Not working")
you will notice you get an ouput of Not working the reason is for object None is regarded as False same applies for some other data type , for integer, as long as a value is zero (0) it will take it as False
So in your case, if num % 2 return 0 then you will have
'odd' if 0 else 'even' # will will return 'even'
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
This question already has answers here:
How to test multiple variables for equality against a single value?
(31 answers)
Closed 6 years ago.
Why does the following evaluates to False in Python?
6==(5 or 6)
False
'b'==('a' or 'b')
False
The first expression evaluates (5 or 6) first, which evaluates to 5 because 5 is truthy. 5 is NOT equal to 6 so it returns False.
The second expression evaluates ('a' or 'b') first, which evaluates to 'a' for the same reason as above. 'a' is NOT equal to 'b' so it returns False.
A good example to explain this would be to try to put a falsey value as the first part of the or expression like 6 == ([ ] or 6) or 6 == (None or 6). Both of these will return true because the or statement will evaluate to the truthy value (in each case it is 6).
There are a couple of ways to create the statement I think you want. The first would be to use in like 6 in (6,5). The second way would be to expand your boolean expression to read like this (6 == 5) or (6 == 6). Both of these will return True.
The condition within parentheses is evaluated first. So
6==(5 or 6)
evaluates to
6==(5) # since 5 != 0 (True), the second operand is not evaluated
which is False. Same goes for the second one. ('a' != None)
Try:
>>>6 == (6 or 5)
True
What's going on? Try:
>>5 or 6
5
I'm not totally sure why "5 or 6" evaluates to 5, but I would just try writing that expression differently.
But there is a caveat:
>> 5 == (0 or 5)
True
Because 0 is not truth-worthy, hence the bracket result in 5.
This question already has answers here:
Is False == 0 and True == 1 an implementation detail or is it guaranteed by the language?
(3 answers)
Closed 8 years ago.
Can someone help to explain the following:
1 and 5
5 and 1
The above gives 5 and 1 respectively. Q1: Why is the and operator not commutative?
Next:
1==True # gives True
However:
5==True
5==False
both give False. Q2: Why?
https://docs.python.org/2/library/stdtypes.html section 5.1 says "... All other values are considered True", so 5 should be True.
From the documentation:
The expression x and y first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.
The expression x or y first evaluates x; if x is true, its value is returned; otherwise, y is evaluated and the resulting value is returned.
Note that here, if x is false means if bool(x) == False.
The answer to your first question about and is that the result of the and is the value of the first expression if it is False-like (0, False, None, etc.), otherwise it is the value of the second expression. A bunch of programming languages share this sort of construct; in some languages like Bash and Perl it's idiomatic to rely on it extensively. In Python we mostly use and for regular boolean logic and rely on it less often for short-circuiting.
As for 1==True being true but 5==True being false, well, frankly I wish 1==True also returned false but obviously it's too late to change it now. :)
In answer to your second part:
It's true that all non-zero integers are "Truthy" but this does not mean that 5 == True will return True. The == operator is comparing value and, when comparing values, 5 is not equal to True. If you compare bool(5) == True then that will return True. When you do if 5: what you actually are doing is if bool(5):.
The reason that 1 == True returns True is that in Python the boolean class is a subclass of int, with True being represented by 1 and False being represented by 0. So 1 == True returns True because they are equal.
Note that, as discussed in this question, this is NOT GUARANTEED in Python 2.x as True and False can be re-defined. In Python 3.x they are keywords which will always be equal to 1 and 0, respectively.
This question already has answers here:
Does Python have a ternary conditional operator?
(31 answers)
How do "and" and "or" act with non-boolean values?
(8 answers)
Closed 4 months ago.
For some reason this function confused me:
def protocol(port):
return port == "443" and "https://" or "http://"
Can somebody explain the order of what's happening behind the scenes to make this work the way it does.
I understood it as this until I tried it:
Either A)
def protocol(port):
if port == "443":
if bool("https://"):
return True
elif bool("http://"):
return True
return False
Or B)
def protocol(port):
if port == "443":
return True + "https://"
else:
return True + "http://"
Is this some sort of special case in Python, or am I completely misunderstanding how statements work?
It's an old-ish idiom; inserting parentheses to show priority,
(port == "443" and "https://") or "http://"
x and y returns y if x is truish, x if x is falsish; a or b, vice versa, returns a if it's truish, otherwise b.
So if port == "443" is true, this returns the RHS of the and, i.e., "https://". Otherwise, the and is false, so the or gets into play and returns `"http://", its RHS.
In modern Python, a better way to do translate this old-ish idiom is:
"https://" if port == "443" else "http://"
and returns the right operand if the left is true. or returns the right operand if the left is false. Otherwise they both return the left operand. They are said to coalesce.
C and X or Y is the long-running early attempt by Python users to proxy for C ? X : Y
For the most part it works, except if X is False -- this has led to many bugs in Python code, so in the Python FAQ, you'll find the more correct solution being (C and [X] or [Y])[0] because a list with a single element, regardless of its evaluated Boolean value, is always True! For example: [None] is True but None isn't. The OP's example above works because the string representing X is not empty.
However, all this changed in Python 2.5, when the ternary or conditional operator was added to the language, allowing you to use the cleaner X if C else Y as stated in other posts here. If you see code using the older format, it's because the user has been a long time Python programmer who hasn't adopted the new syntax yet, they cut-n-paste other old code, or their employer is still using 2.4.x (or earlier releases), etc.
This is an ugly hack that is not recommended. It works because of the short-circuiting behaviour of and and or and that they return the one of their arguments rather than a boolean value. Using this technique gives a risk of introducing hard-to-find bugs, so don't use it in new code.
Here's an example of how the and/or idiom can give an unexpected result:
>>> foo = 'foobar'
>>> bar = 'foobar'
>>> x = 0
>>> y = 1
>>> (foo == bar) and x or y # Will this return the value of x if (foo == bar)?
1
Prefer instead the newer notation:
return "https://" if port == "443" else "http://"
You may want to read up on the "and / or trick" of Python in this article The Peculiar Nature of And and Or in Python. It's a bit like the IIF() in VBA or VB, or ?: in C-style languages.
This construction works because it 'unfolds' to the following code:
a and b -->
if a:
return b
else:
return a
a or b -->
if a:
return a
else:
return b
With all the good answers, I found these statements help me remember this better and fit how my brain works (and hopefully for for some more out there) :
“and" returns the first False item (e.g., None, “”, [], (), {}, 0) or the last item if none (e.g. no False found)
“or" returns the first True item or the last item (e.g. no True found)**
In summary:
they all return the first item that decides the outcome of the statement. (In the worst case, the last item in the sequence)
Note this rule also applies to a chained all "and" or all "or" statement