How does the "for" inline command work?

11

I did a question regarding a Python algorithm, but in resolution of the user Anderson Carlos Woss he used a type of% inline that I had never seen and that left me confused.

Here is the code snippet corresponding to for :

groups = [text[i:i+key].ljust(key, "*") for i in range(0, len(text), key)]

Can anyone explain to me what this expression for inline is and how does it work?

    
asked by anonymous 27.09.2017 / 13:54

2 answers

14

This form is called list comprehension, or in English list comprehensions . It is nothing more than a simplified way of writing a for loop. In this case I have even misused it, because the final code was not as readable as it should be in a Python code, but the equivalent code would be:

groups = []

for i in range(0, len(text), key):
    value = text[i:i+key]          # Pega o trecho da string de i até i+key
    value = value.ljust(key, "*")  # Garante que a string possua "key" caracteres, adicionando *
    groups.append(value)           # Adiciona o valor final à lista

This code above, for practical purposes, does exactly the same thing as the line presented in the question:

groups = [text[i:i+key].ljust(key, "*") for i in range(0, len(text), key)]

This syntax is set to make the code more concise and much more readable - at least that's the goal (not always used correctly hehe). In unofficial sources, one can read that list comprehension is even faster than a for normal due primarily to internal language implementations. Particularly I have never tried to prove this in practice and I do not remember seeing any official source that proves this, but at least it has the same performance, so you can use it without fear.

In addition, you can use nested form list comprehension, for example, to cycle through an "array", which requires a for for rows and another for columns.

matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
]

double_matrix = [[2*matrix[i][j] for j in range(3)] for i in range(3)]

The result would be the "matrix" multiplied by 2:

[
  [ 2,  4,  6],
  [ 8, 10, 12],
  [14, 16, 18]
]

Because the equivalent code would be:

matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
]

double_matrix = []

for i in range(3):
    row = []
    for j in range(3):
        row.append(2*matrix[i][j])
    double_matrix.append(row)

References

Official Documentation: List Comprehensions

This syntax is also valid for defining dictionaries. Assuming we want to create a dictionary with integer keys from 0 to 4, whose value in the dictionary refers to double the key. With a for loop, we could do:

d = {}

for i in range(5):
    d[i] = 2*i

print(d)
  

See working at Ideone .

The syntax using dict comprehensions would be:

d = {i: 2*i for i in range(5)}
  

See working at Ideone .

The main difference is that while list comprehension is defined between brackets, [] , which is list syntax, dictionary comprehension is defined between braces, {} , which is the syntax of dictionaries, in addition to setting the key / value pair and i: 2*i .

That said, it is possible to think that it would also be possible to define a tuple with this syntax only using in parentheses, () , which is the tuple syntax. Wrong. The tuple is an immutable type of Python and therefore could not be changed next to the for loop, but that does not mean that the syntax using the parentheses is wrong.

In fact, when you use parentheses, what is defined is a generator. That is, do something like:

g = (2*i for i in range(5))
  

See working at Ideone .

It would be the same as:

def temp():
    for i in range(5):
        yield 2*i

g = temp()

In these cases, you could iterate over the generator or simply convert it to a list:

l = list(g)

print(l)
  

See working at Ideone .

In some cases it would be possible to omit the parentheses, so when you see the syntax without the parentheses, know that it is also a definition of a parent. To cite an example, calculate the sum of the values between 0 and 5:

s = sum(i for i in range(5))
  

See working at Ideone .

    
27.09.2017 / 14:01
9

This is basically the same as writing

for i in range(0, len(text), key)]
    groups = groups + [text[i:i + key].ljust(key, "*")

Do you know other languages? The range() generates a numeric sequence as if it were

for (int i = 0; i < len(text); i+= key)

The ljust() function makes a padding then it repeats a given character as many times as necessary until it fills as desired. It does this with, an object obtained previously with the expression

text[i:i + key]

This is a slice , ie it takes a collection of In this case, a collection of characters, also known as string , establishes which character will start to get, in this case the value of i and what position to take, in the case i + key , or either, it takes the amount of characters from the for increment.

for documentation . And on flow control structures in general .

    
27.09.2017 / 14:03