Por que não há compreensão de tupla no Python?

Como todos sabemos, há compreensão da lista, como

[i for i in [1, 2, 3, 4]] 

e há uma compreensão do dictionary, como

 {i:j for i, j in {1: 'a', 2: 'b'}.items()} 

mas

 (i for i in (1, 2, 3)) 

vai acabar em um gerador, não em uma compreensão de tuple . Por que é que?

Meu palpite é que uma tuple é imutável, mas isso não parece ser a resposta.

    Você pode usar uma expressão de gerador:

     tuple(i for i in (1, 2, 3)) 

    mas parênteses já foram tomadas para .. expressões geradoras.

    Raymond Hettinger (um dos principais desenvolvedores do Python) disse o seguinte sobre as tuplas em um tweet recente :

    #python tip: Geralmente, as listas são for looping; tuplas para estruturas. As listas são homogêneas; tuplos heterogêneos. Lista de comprimento variável.

    Isso (para mim) apóia a idéia de que, se os itens em uma sequência estiverem relacionados o suficiente para serem gerados por um gerador, então deve ser uma lista. Embora uma tupla seja iterável e pareça simplesmente uma lista imutável, é realmente o equivalente em Python de uma estrutura C:

     struct { int a; char b; float c; } foo; struct foo x = { 3, 'g', 5.9 }; 

    torna-se em Python

     x = (3, 'g', 5.9) 

    Desde o Python 3.5 , você também pode usar a syntax de desempacotamento para uma compreensão de tupla:

     *(x for x in range(10)), 

    A compreensão funciona por meio de um loop ou iterando sobre itens e atribuindo-os a um contêiner, um Tuple não pode receber atribuições.

    Uma vez que uma Tupla é criada, ela não pode ser anexada, estendida ou atribuída. A única maneira de modificar um Tuple é se um dos seus objects puder ser atribuído a ele (é um contêiner que não é tuple). Porque o Tuple só está segurando uma referência a esse tipo de object.

    Além disso – uma tupla tem sua própria tuple() construtor tuple() que você pode fornecer a qualquer iterador. O que significa que, para criar uma tupla, você poderia fazer:

     tuple(i for i in (1,2,3)) 

    Meu melhor palpite é que eles ficaram sem colchetes e não acharam que seria útil o suficiente para adicionar uma syntax “feia” …

    Como outro pôster macm , a maneira mais rápida de criar uma tupla a partir de um gerador é tuple([generator]) .


    Comparação de desempenho

    • Compreensão da lista:

       $ python3 -m timeit "a = [i for i in range(1000)]" 10000 loops, best of 3: 27.4 usec per loop 
    • Tupla da compreensão da lista:

       $ python3 -m timeit "a = tuple([i for i in range(1000)])" 10000 loops, best of 3: 30.2 usec per loop 
    • Tuple do gerador:

       $ python3 -m timeit "a = tuple(i for i in range(1000))" 10000 loops, best of 3: 50.4 usec per loop 
    • Tuple da descompactação:

       $ python3 -m timeit "a = *(i for i in range(1000))," 10000 loops, best of 3: 52.7 usec per loop 

    Minha versão do python :

     $ python3 --version Python 3.6.3 

    Portanto, você deve sempre criar uma tupla a partir de uma compreensão de lista, a menos que o desempenho não seja um problema.

    As tuplas não podem ser adicionadas de forma eficiente como uma lista.

    Assim, uma compreensão de tupla precisaria usar uma lista internamente e depois converter em uma tupla.

    Isso seria o mesmo que você faz agora: tuple ([compreensão])

    Eu acredito que é simplesmente por uma questão de clareza, nós não queremos bagunçar a linguagem com muitos símbolos diferentes. Também uma compreensão de tuple nunca é necessária , uma lista pode ser usada apenas com diferenças de velocidade insignificantes, ao contrário de uma compreensão de dictionary em oposição a uma compreensão de lista.

    Parênteses não criam uma tupla. aka um = (dois) não é uma tupla. A única maneira de contornar é um = (dois) ou um = tupla (dois). Então uma solução é:

     tuple(i for i in myothertupleorlistordict) 

    Podemos gerar tuplas a partir de uma compreensão de lista. O seguinte adiciona dois números sequencialmente em uma tupla e fornece uma lista de números de 0 a 9.

     >>> print k [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99] >>> r= [tuple(k[i:i+2]) for i in xrange(10) if not i%2] >>> print r [(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]