Como todos sabemos, há compreensão de lista, como
[i for i in [1, 2, 3, 4]]
e há compreensão de dicionário, como
{i:j for i, j in {1: 'a', 2: 'b'}.items()}
mas
(i for i in (1, 2, 3))
terminará em um gerador, não em uma tuple
compreensão. Por que é que?
Meu palpite é que a tuple
é imutável, mas isso não parece ser a resposta.
{i:j for i,j in {1:'a', 2:'b'}}
should be{i:j for i,j in {1:'a', 2:'b'}.items()}
Respostas:
Você pode usar uma expressão geradora:
mas parênteses já foram usados para ... expressões geradoras.
fonte
list(i for i in (1,2,3))
. Eu realmente acho que é simplesmente porque não é uma sintaxe limpa para ele (ou pelo menos ninguém pensou em um)list(i for i in (1, 2, 3))
é uma expressão geradora que gera uma lista,set(i for i in (1, 2, 3))
gera um conjunto. Isso significa que a sintaxe de compreensão não é necessária? Talvez não, mas é muito útil. Nos casos raros em que você precisa de uma tupla, a expressão do gerador funcionará, é clara e não requer a invenção de outra chave ou suporte.[thing for thing in things]
constrói uma lista muito mais rápido quelist(thing for thing in things)
. Uma compreensão de tupla não seria inútil;tuple(thing for thing in things)
tem problemas de latência etuple([thing for thing in things])
pode ter problemas de memória.A list or set or dict comprehension is just syntactic sugar to use a generator expression
? Está causando confusão quando as pessoas vêem isso como um meio equivalente a um fim. Não é um açúcar tecnicamente sintático, pois os processos são realmente diferentes, mesmo que o produto final seja o mesmo.Raymond Hettinger (um dos principais desenvolvedores do Python) disse isso sobre tuplas em um tweet recente :
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:
torna-se em Python
fonte
operator.itemgetter
nesse caso.tuple(obj[item] for item in items)
diretamente. No meu caso, eu estava incorporando isso em uma compreensão de lista para fazer uma lista de registros de tupla. Se eu precisar fazer isso repetidamente em todo o código, o itemgetter ficará ótimo. Talvez o itemgetter seja mais idiomático de qualquer maneira?Desde o Python 3.5 , você também pode usar a
*
sintaxe de descompactação splat para descompactar uma expressão de gerador:fonte
tuple(list(x for x in range(10)))
( os caminhos de código são idênticos , com os dois construindo umlist
, com a única diferença é que a etapa final é criar um atuple
partir dolist
e jogar fora olist
quando umatuple
saída É necessário). Significa que você realmente não evita um par de temporários.*(x for x in range(10))
não funciona. Eu entendoSyntaxError: can't use starred expression here
. No entantotuple(x for x in range(10))
funciona.Como outro pôster
macm
mencionado, a maneira mais rápida de criar uma tupla a partir de um gerador étuple([generator])
.Comparação de desempenho
Compreensão da lista:
Tupla da compreensão da lista:
Tupla do gerador:
Tupla de desembalar:
Minha versão do python :
Portanto, você deve sempre criar uma tupla a partir de uma compreensão da lista, a menos que o desempenho não seja um problema.
fonte
tuple
listcomp requer um pico de uso de memória com base no tamanho combinado do finaltuple
elist
.tuple
de um genexpr, embora mais lento, significa que você paga apenas pelo finaltuple
, não temporáriolist
(o próprio genexpr ocupa uma memória aproximadamente fixa). Geralmente não é significativo, mas pode ser importante quando os tamanhos envolvidos são enormes.A compreensão funciona repetindo ou iterando itens e atribuindo-os a um contêiner, uma Tupla não pode receber atribuições.
Depois que uma tupla é criada, ela não pode ser anexada, estendida ou atribuída a. A única maneira de modificar uma tupla é se um de seus objetos pode ser atribuído a ele (é um contêiner não-tupla). Porque a Tupla está apenas mantendo uma referência a esse tipo de objeto.
Além disso - uma tupla tem seu próprio construtor,
tuple()
que você pode fornecer a qualquer iterador. O que significa que, para criar uma tupla, você pode fazer:fonte
lst = [x for x in ...]; x.append()
?Meu melhor palpite é que eles ficaram sem colchetes e não acharam que seria útil o suficiente para garantir a adição de uma sintaxe "feia" ...
fonte
{*()}
, embora feio, funciona como um conjunto vazio literal!set()
:){*[]}
é estritamente inferior às outras opções; a string vazia e vaziatuple
, sendo imutáveis, são singletons, portanto, não é necessário temporário para construir a vaziaset
. Por outro lado, o vaziolist
não é um singleton, então você realmente precisa construí-lo, usá-lo para construirset
e destruí-lo, perdendo qualquer vantagem trivial de desempenho que o operador de um olho só oferece.As tuplas não podem ser anexadas com eficiência como uma lista.
Portanto, uma compreensão da tupla precisaria usar uma lista internamente e depois converter em uma tupla.
Seria o mesmo que você faz agora: tupla ([compreensão])
fonte
Parênteses não criam uma tupla. aka um = (dois) não é uma tupla. A única maneira de contornar isso é um = (dois) ou um = tupla (dois). Portanto, uma solução é:
fonte
Creio que é simplesmente por uma questão de clareza, não queremos desordenar a linguagem com muitos símbolos diferentes. Além disso, uma
tuple
compreensão nunca é necessária ; uma lista pode ser usada apenas com diferenças insignificantes de velocidade, ao contrário de uma compreensão de ditado em oposição a uma compreensão de lista.fonte
Podemos gerar tuplas a partir de uma compreensão da lista. O seguinte adiciona dois números sequencialmente a uma tupla e fornece uma lista dos números 0-9.
fonte