Em Python (2 e 3). Sempre que usamos o fatiamento de lista, ele retorna um novo objeto, por exemplo:
l1 = [1,2,3,4]
print(id(l1))
l2 = l1[:]
print(id(l2))
Resultado
>>> 140344378384464
>>> 140344378387272
Se a mesma coisa é repetida com tupla, o mesmo objeto é retornado, por exemplo:
t1 = (1,2,3,4)
t2 = t1[:]
print(id(t1))
print(id(t2))
Resultado
>>> 140344379214896
>>> 140344379214896
Seria ótimo se alguém pudesse esclarecer por que isso está acontecendo. Ao longo da minha experiência com o Python, fiquei com a impressão de que a fatia vazia retorna um novo objeto.
Meu entendimento é que ele está retornando o mesmo objeto que as tuplas são imutáveis e não há sentido em criar uma nova cópia dele. Mas, novamente, isso não é mencionado nos documentos em nenhum lugar.
l2 = tuple(iter(l1))
ignora a otimizaçãoPyTuple_GetSlice
foi documentada incorretamente depois de ver sua pergunta. Os documentos foram corrigidos (foi o problema bpo38557 ).Respostas:
As implementações são livres para retornar instâncias idênticas para tipos imutáveis (no CPython, às vezes você pode ver otimizações semelhantes para seqüências de caracteres e números inteiros). Como o objeto não pode ser alterado, não há nada no código do usuário que precise se preocupar se ele possui uma instância exclusiva ou apenas outra referência a uma instância existente.
Você pode encontrar o curto-circuito no código C aqui .
Este é um detalhe de implementação, observe que o pypy não faz o mesmo.
fonte
a->ob_item
é como(*a).ob_item
, isto é, obtém o membro chamadoob_item
doPyTupleObject
que a está apontando, e o + ilow avança para o início da fatia.É um detalhe de implementação. Como as listas são mutáveis, é
l1[:]
necessário criar uma cópia, porque você não espera que as alteraçõesl2
sejam afetadasl1
.Como uma tupla é imutável , porém, não há nada que você possa fazer
t2
que possa afetar det1
maneira visível, portanto o compilador é livre (mas não obrigatório ) para usar o mesmo objeto parat1
et1[:]
.fonte
No Python 3. *
my_list[:]
é o açúcar sintático paratype(my_list).__getitem__(mylist, slice_object)
where:slice_object
é um objeto de fatia criado a partirmy_list
dos atributos (comprimento) e da expressão[:]
. Objetos que se comportam dessa maneira são chamados de subscritos no modelo de dados Python, veja aqui . Para listas e tuplas__getitem__
é um método interno.No CPython, e para listas e tuplas,
__getitem__
é interpretado pela operação de bytecode,BINARY_SUBSCR
que é implementada para tuplas aqui e para listas aqui .No caso de tuplas, percorrendo o código, você verá que, neste bloco de código ,
static PyObject* tuplesubscript(PyTupleObject* self, PyObject* item)
retornará uma referência à mesmaPyTupleObject
que obteve como argumento de entrada, se o item for do tipoPySlice
e a fatia for avaliada para toda a tupla.Agora você examina o código
static PyObject * list_subscript(PyListObject* self, PyObject* item)
e vê por si mesmo que, independentemente da fatia, um novo objeto de lista é sempre retornado.fonte
start:stop
fatia no tipo embutido, incluindotup[:]
, não passaBINARY_SUBSCR
. A fatia estendidastart:stop:step
passa por assinatura, no entanto.Não tenho certeza disso, mas parece que o Python fornece um novo ponteiro para o mesmo objeto para evitar a cópia, pois as tuplas são idênticas (e como o objeto é uma tupla, é imutável).
fonte