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

.

+3


source to share


2 answers


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.

+4


source


Quote doc :

The expression x and y

evaluates first x

; if x

false, its value is returned; otherwise, it is evaluated y

and the resulting value is returned.

The expression x or y

evaluates first x

; if x

true, its value is returned; otherwise, it is evaluated y

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 result g.lower()

    will be executed
  • otherwise it g

    will be accepted

As you can see, this is the same as in list3

.

+1


source







All Articles