How does this list comprehension work?
list1 = ['Hello', 10, None]
list2 = [g.lower() for g in list1 if isinstance(g, str)]
list3 = [g.lower() if isinstance(g,str) else g for g in list1]
list4 = [isinstance(g, str) and g.lower() or g for g in list1]
If I want to convert a string in list
to lowercase, I can use the in method list2
and the output will be ['hello']
.
In addition to this conversion, if I want to store integers (in this case 10
) and None
, the methods in both in list3
and in list4
will work, and the output will be ['hello', 10, None]
.
My question is that I cannot figure out how the method works in list4
.
To start writing code like this:
condition and value1 or value2
was how people used the ternary conditional operator in Python before:
value1 if condition else value2
was introduced in version 2.5 due to PEP 0308 . Using the old method is now deprecated in favor of a slightly more efficient and much more readable newer method.
Old method works because of the way and
and or
work in Python. Instead of returning boolean results, as in most other languages, these operators return values.
Execution a and b
returns a
if a
evaluated as False
; otherwise, it returns b
:
>>> 0 and 1
0
>>> 1 and 0
0
>>> 1 and 2
2
>>>
Execution a or b
returns a
if a
evaluated as True
; otherwise, it returns b
:
>>> 1 or 0
1
>>> 0 or 1
1
>>> 1 or 2
1
>>>
Also, in case you don't know, 0
is evaluated as False
, and every other number matches True
.
Coming to your code, these are:
isinstance(g, str) and g.lower() or g
is actually interpreted by Python as:
(isinstance(g, str) and g.lower()) or g
Now if isinstance(g, str)
returns False
( g
not a string):
(False and g.lower()) or g
False
returns and
:
False or g
and then or
returns g
. Thus, we avoided calling .lower()
for a non-string type.
If, however, isinstance(g, str)
returns True
( g
- string):
(True and g.lower()) or g
and
returns g.lower()
:
g.lower() or g
and then or
returns g.lower()
, which is great because g
is a string.
To summarize, these two expressions:
g.lower() if isinstance(g,str) else g
isinstance(g, str) and g.lower() or g
are functionally equivalent. But please use the first one! The other is terrible for readability.
source to share
Quote doc :
The expression
x and y
evaluates firstx
; ifx
false, its value is returned; otherwise, it is evaluatedy
and the resulting value is returned.The expression
x or y
evaluates firstx
; ifx
true, its value is returned; otherwise, it is evaluatedy
and the resulting value is returned.
Due to the rules, the precedence is isinstance(g, str) and g.lower() or g
actually evaluated as
(isinstance(g, str) and g.lower()) or g
(multiplication has higher priority than addition).
This basically means the following:
- If
isinstance(g, str)
true, the resultg.lower()
will be executed - otherwise it
g
will be accepted
As you can see, this is the same as in list3
.
source to share