No Python, existem dois tipos semelhantes - lista (lista) e tupla (tupla). A diferença mais famosa entre os dois é que as tuplas são imutáveis.
Você não pode alterar objetos na tupla:
>>> a = (1,2,3) >>> a[0] = 10 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment
Mas você pode modificar objetos mutáveis dentro de uma tupla:
>>> b = (1,[1,2,3],3) >>> b[1] [1, 2, 3] >>> b[1].append(4) >>> b (1, [1, 2, 3, 4], 3)
Dentro do CPython (intérprete padrão), a lista e a tupla são implementadas como uma folha de ponteiros (links) para objetos Python, ou seja, fisicamente, eles não armazenam objetos próximos um do outro. Quando você exclui um objeto da lista, a referência a esse objeto é excluída. Se outra pessoa se referir ao objeto, ele continuará na memória.
Tuplas
Apesar do fato de as tuplas serem muito menos comuns no código e não tão populares, esse é um tipo muito fundamental que o Python constantemente usa para fins internos.
Você pode não perceber, mas usa tuplas quando:
- trabalhar com argumentos ou parâmetros (eles são armazenados como tuplas)
- retorna duas ou mais variáveis de uma função
- itere chaves de valor em um dicionário
- use formatação de string
Normalmente, o script mais simples usa milhares de tuplas:
>>> import gc >>> def type_stats(type_obj): ... count = 0 ... for obj in gc.get_objects(): ... if type(obj) == type_obj: ... count += 1 ... return count ... >>> type_stats(tuple) 3136 >>> type_stats(list) 659 >>> import pandas >>> type_stats(tuple) 6953 >>> type_stats(list) 2455
Listas vazias vs tuplas vazias
Uma tupla vazia funciona como um singleton, ou seja, sempre há apenas uma tupla vazia na memória de um script Python em execução. Todas as tuplas vazias se referem simplesmente ao mesmo objeto, isso é possível porque as tuplas são imutáveis. Essa abordagem economiza muita memória e acelera o processo de trabalho com tuplas vazias.
>>> a = () >>> b = () >>> a is b True >>> id(a) 4409020488 >>> id(b) 4409020488 >>>
Mas isso não funciona com listas, porque elas podem ser alteradas:
>>> a = [] >>> b = [] >>> a is b False >>> id(a) 4465566920 >>> id(b) 4465370632
Otimizando a alocação de memória para tuplas
Para reduzir a fragmentação da memória e acelerar a criação de tuplas, o Python reutiliza tuplas antigas que foram excluídas. Se uma tupla consiste em menos de 20 elementos e não é mais usada, em vez de excluí-la, o Python a coloca em uma lista especial, que armazena as tuplas livres para reutilização.
Essa lista é dividida em 20 grupos, onde cada grupo é uma lista de tuplas de tamanho n, onde n é de 0 a 20. Cada grupo pode armazenar até 2.000 tuplas gratuitas. O primeiro grupo armazena apenas um elemento e é uma lista de uma tupla vazia.
>>> a = (1,2,3) >>> id(a) 4427578104 >>> del a >>> b = (1,2,4) >>> id(b) 4427578104
No exemplo acima, podemos ver que aeb têm o mesmo endereço na memória. Isso se deve ao fato de termos instantaneamente obtido uma tupla do mesmo tamanho.
Otimizando a alocação de memória para listas
Como as listas estão sujeitas a alterações, a mesma otimização que no caso das tuplas não pode mais ser acionada. Apesar disso, as listas usam otimizações semelhantes destinadas a listas vazias. Se a lista vazia for excluída, também poderá ser reutilizada no futuro.
>>> a = [] >>> id(a) 4465566792 >>> del a >>> b = [] >>> id(b) 4465566792
Redimensionar lista
Para evitar a sobrecarga das listas de redimensionamento constante, o Python não a redimensiona sempre que necessário. Em vez disso, cada lista possui um conjunto de células adicionais ocultas ao usuário, mas que posteriormente podem ser usadas para novos elementos. Assim que as células ocultas terminam, o Python adiciona espaço extra para novos elementos. E ele faz isso com uma boa margem, o número de células ocultas é selecionado com base no tamanho atual da lista - quanto maior, mais slots ocultos adicionais para novos elementos.
Essa otimização é especialmente útil quando você tenta adicionar muitos elementos em um loop.
O padrão de crescimento do tamanho da lista é mais ou menos assim: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
Por exemplo, se você deseja adicionar um novo elemento a uma lista com 8 elementos, não haverá células livres e o Python expandirá imediatamente seu tamanho para 16 células, onde 9 delas serão ocupadas e visíveis ao usuário.
Fórmula de dimensionamento do Python:
>>> def get_new_size(n_items): ... new_size = n_items + (n_items // 2 ** 3) ... if n_items < 9: ... new_size += 3 ... else: ... new_size += 6 ... ... return new_size ... >>> get_new_size(9) 16
Velocidade
Se compararmos esses dois tipos em velocidade, em média, em um hospital, as tuplas são um pouco mais rápidas que as listas. Raymond Hettinger tem uma ótima explicação para a diferença de velocidade no
fluxo de
pilha .
PS: Eu sou o autor deste artigo, você pode fazer qualquer pergunta.