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 the string in list to lowercase, I can use the method in list2 and the output will be ['hello'].
In addition to this conversion, if I want to keep integers (which is 10 in this case) and None, the methods in both list3 and list4 will work and the output will be ['hello', 10, None].
My question is that I can't understand how the method in list4 works.
To start, writing code like this:
condition and value1 or value2
was how people implemented a ternary conditional operator in Python before the:
value1 if condition else value2
conditional expression was introduced in version 2.5 because of PEP 0308. Using the old method is now deprecated in favor of the slightly more efficient and far more readable newer method.
The old method works because of how and and or operate in Python. Instead of returning boolean results like in most other languages, these operators return values.
Doing a and b returns a if a evaluates to False; otherwise, it returns b:
>>> 0 and 1
0
>>> 1 and 0
0
>>> 1 and 2
2
>>>
Doing a or b returns a if a evaluates to True; otherwise, it returns b:
>>> 1 or 0
1
>>> 0 or 1
1
>>> 1 or 2
1
>>>
Also, in case you do not know, 0 evaluates to False while every other number evaluates to True.
Coming to your code, this:
isinstance(g, str) and g.lower() or g
is actually interpreted by Python like:
(isinstance(g, str) and g.lower()) or g
Now if isinstance(g, str) returns False (g is not a string):
(False and g.lower()) or g
False is returned by and:
False or g
and then or returns g. Thus, we avoided calling .lower() on a non-string type.
If however isinstance(g, str) returns True (g is a string):
(True and g.lower()) or g
and returns g.lower():
g.lower() or g
and then or returns g.lower(), which is fine because g is a string.
Summed up, 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!! The other is terrible for readability.
Quoting the doc:
The expression
x and yfirst evaluatesx; ifxis false, its value is returned; otherwise,yis evaluated and the resulting value is returned.The expression
x or yfirst evaluatesx; ifxis true, its value is returned; otherwise,yis evaluated and the resulting value is returned.
Because of precedence rules, isinstance(g, str) and g.lower() or g is actually evaluated as
(isinstance(g, str) and g.lower()) or g (multiplication is of higher precedence than addition).
That basically means the following:
isinstance(g, str) is true, result of g.lower() will be takeng will be takenAs you see, it's the same thing that you have in list3 operation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With