Loop aninhado em Python de uma linha

Escrevi esta função em python que transpõe uma matriz:

def transpose(m):
    height = len(m)
    width = len(m[0])
    return [ [ m[i][j] for i in range(0, height) ] for j in range(0, width) ]

No processo, percebi que não entendo completamente como um loop aninhado em pytohn de uma linha funciona. Por favor me ajude a entender respondendo as seguintes perguntas:

  • Qual é a ordem em que esse loop for é executado?
  • Se eu tivesse um loop for triplamente aninhado, que ordem ele executaria?
  • O que seria igual ao loop for não aninhado igual?

Dado o código abaixo:

[ function(i,j) for i,j in object ]

  • Que tipo de objeto deve ser para usar essa estrutura de loop for?
  • Qual é a ordem em que i e j são atribuídos aos elementos no objeto?
  • Pode ser simulado por uma estrutura de loop for diferente?
  • Este loop for pode ser aninhado com uma estrutura for loop semelhante ou diferente? E como ficaria?

As compreensões de lista são quase as mesmas que os loops for, mas geralmente são mais rápidas do que usar um loop for.

Esta compreensão de lista e o loop aninhado em Python abaixo tem o mesmo resultado:

[(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
combs = []
for x in [1,2,3]:
  for y in [3,1,4]:
     if x != y:
        combs.append((x, y))

A principal diferença entre uma compreensão de lista e um loop for é que a parte final do loop for (onde você faz algo com o seu código) vem no início e não no final.

Agora respondendo às suas perguntas:

  • Este exemplo que você deu não é um loop for e sim uma compreensão de lista

  • Geralmente aninha como loops for, da direita para a esquerda. Mas a sintaxe de compreensão de lista é mais complexa.

  • Não entendi direito a terceira pergunta.

  • Para usar esta estrutura de loop aninhado em Python de uma linha (ou qualquer tipo de loop, na verdade) o objeto precisa ser um iterável. Qualquer objeto que possa gerar um conjunto (finito) de elementos. Estes incluem qualquer container, listas, conjuntos, geradores, etc.

  • Eles são atribuídos exatamente na mesma ordem em que são gerados a partir de cada lista, como se estivessem em um loop for aninhado (para sua primeira compreensão, você obteria 1 elemento para i, depois cada valor de j, 2º elemento em i, então todo valor de j, etc.)

  • Sim, como mostrado acima, dá para usar estrutura de loop for diferentes para obter o mesmo resultado.

  • Claro, mas não é uma boa ideia. Aqui, por exemplo, retorna uma lista de listas de caracteres:

[[ch for ch in word] for word in ("apple", "banana", "pear", "the", "hello")]