Waarom is er geen tuple-begrip in Python?

Zoals we allemaal weten, is er begrip van lijsten, zoals

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

en er is woordenboekbegrip, zoals

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

maar

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

zal eindigen in een generator, niet in een tuple-begrip. Waarom is dat?

Mijn gok is dat een tupleonveranderlijk is, maar dit lijkt niet het antwoord te zijn.


Antwoord 1, autoriteit 100%

U kunt een generatoruitdrukking gebruiken:

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

maar haakjes zijn al gebruikt voor … generator-expressies.


Antwoord 2, autoriteit 16%

Raymond Hettinger (een van de Python-kernontwikkelaars) had dit te zeggen over tuples in een recente tweet:

#python tip: Over het algemeen zijn lijsten voor looping; tupels voor structs. Lijsten zijn homogeen; tupels heterogeen. Lijsten voor variabele lengte.

Dit ondersteunt (voor mij) het idee dat als de items in een reeks voldoende gerelateerd zijn om te worden gegenereerd door een, nou ja, generator, het een lijst zou moeten zijn. Hoewel een tuple itereerbaar is en gewoon een onveranderlijke lijst lijkt, is het echt het Python-equivalent van een C-struct:

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

wordt in Python

x = (3, 'g', 5.9)

Antwoord 3, autoriteit 13%

Sinds Python 3.5kun je ook splat *syntaxis uitpakken om een generatoruitdrukking uit te pakken:

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

Antwoord 4, autoriteit 8%

Zoals een andere poster macmal zei, is de snelste manier om een tuple van een generator te maken tuple([generator]).


Prestatievergelijking

  • Lijst begrip:

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

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

    $ python3 -m timeit "a = tuple(i for i in range(1000))"
    10000 loops, best of 3: 50.4 usec per loop
    
  • Tuple van het uitpakken:

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

Mijn versie van python:

$ python3 --version
Python 3.6.3

Je moet dus altijd een tuple maken op basis van een lijstbegrip, tenzij prestatie geen probleem is.


Antwoord 5, autoriteit 5%

Begrijpen werkt door items te herhalen of te herhalen en ze toe te wijzen aan een container, een Tuple kan geen opdrachten ontvangen.

Als een Tuple eenmaal is gemaakt, kan deze niet worden toegevoegd aan, uitgebreid of toegewezen aan. De enige manier om een Tuple te wijzigen is als een van zijn objecten zelf kan worden toegewezen aan (is een niet-tuple container). Omdat de Tuple alleen een verwijzing naar dat soort object vasthoudt.

Ook – een tuple heeft zijn eigen constructor tuple()die je aan elke iterator kunt geven. Wat betekent dat om een tuple te maken, je het volgende zou kunnen doen:

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

Antwoord 6, autoriteit 2%

Mijn beste gok is dat ze geen haakjes meer hadden en niet dachten dat het nuttig genoeg zou zijn om een “lelijke” syntaxis toe te voegen …


Antwoord 7, autoriteit 2%

Tuples kunnen niet efficiënt worden toegevoegd zoals een lijst.

Dus een tuple-begrip zou intern een lijst moeten gebruiken en vervolgens naar een tuple moeten converteren.

Dat zou hetzelfde zijn als wat je nu doet : tuple( [comprehension ] )


Antwoord 8

Haakjes maken geen tuple. aka één = (twee) is geen tuple. De enige manier om dit te omzeilen is ofwel één = (twee,) of één = tuple (twee). Een oplossing is dus:

tuple(i for i in myothertupleorlistordict) 

Antwoord 9

Ik geloof dat het voor de duidelijkheid is, we willen de taal niet overladen met te veel verschillende symbolen. Ook is een tuplebegrip nooit nodig, een lijst kan gewoon gebruikt worden met verwaarloosbare snelheidsverschillen, in tegenstelling tot een dict begrip in tegenstelling tot een lijst begrip.


Antwoord 10

Op mijn python (3.5) met behulp van een generator met dequevan collectionsis iets sneller dan gebruik van een listBegrip:

>>> from collections import deque
>>> timeit.timeit(lambda: tuple([i for i in range(10000000)]),number=10)
9.294099200000005
>>> timeit.timeit(lambda: tuple(deque((i for i in range(10000000)))),number=10)
9.007653800000014

Antwoord 11

We kunnen tuples genereren van een lijstbegrip. De volgende voegt u twee cijfers achtereenvolgens in een tuple toe en geeft een lijst van nummers 0-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)]

Other episodes