Considere o seguinte:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
# FAKE METHOD:
items.amount() # Should return 3
Como obtenho o número de elementos na lista items
?
Considere o seguinte:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
# FAKE METHOD:
items.amount() # Should return 3
Como obtenho o número de elementos na lista items
?
Respostas:
Como obter o tamanho de uma lista?
Para encontrar o tamanho de uma lista, use a função interna len
:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
E agora:
len(items)
retorna 3.
Tudo no Python é um objeto, incluindo listas. Todos os objetos têm um cabeçalho de algum tipo na implementação C.
As listas e outros objetos internos similares com um "tamanho" no Python, em particular, têm um atributo chamado ob_size
, onde o número de elementos no objeto é armazenado em cache. Portanto, verificar o número de objetos em uma lista é muito rápido.
Mas se você estiver verificando se o tamanho da lista é zero ou não, não use len
- em vez disso, coloque a lista em um contexto booleano - ele será tratado como False se estiver vazio, True caso contrário .
len(s)
Retorna o comprimento (o número de itens) de um objeto. O argumento pode ser uma sequência (como uma sequência de caracteres, bytes, tupla, lista ou intervalo) ou uma coleção (como um dicionário, conjunto ou conjunto congelado).
len
é implementado com __len__
, a partir dos documentos do modelo de dados :
object.__len__(self)
Chamado para implementar a função interna
len()
. Deve retornar o comprimento do objeto, um número inteiro> = 0. Além disso, um objeto que não define um método__nonzero__()
[no Python 2 ou__bool__()
no Python 3] e cujo__len__()
método retorna zero é considerado falso em um contexto booleano.
E também podemos ver que __len__
é um método de lista:
items.__len__()
retorna 3.
len
(comprimento) deDe fato, vemos que podemos obter essas informações para todos os tipos descritos:
>>> all(hasattr(cls, '__len__') for cls in (str, bytes, tuple, list,
xrange, dict, set, frozenset))
True
len
para testar uma lista vazia ou não vaziaPara testar um comprimento específico, é claro, basta testar a igualdade:
if len(items) == required_length:
...
Mas há um caso especial para testar uma lista de tamanho zero ou o inverso. Nesse caso, não teste a igualdade.
Além disso, não faça:
if len(items):
...
Em vez disso, basta:
if items: # Then we have some items, not empty!
...
ou
if not items: # Then we have an empty list!
...
Eu explico o porquê aqui, mas em resumo, if items
ou if not items
é mais legível e com melhor desempenho.
Embora isso possa não ser útil devido ao fato de que faria muito mais sentido ser uma funcionalidade "pronta para uso", um truque bastante simples seria criar uma classe com uma length
propriedade:
class slist(list):
@property
def length(self):
return len(self)
Você pode usá-lo assim:
>>> l = slist(range(10))
>>> l.length
10
>>> print l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Essencialmente, é exatamente idêntico a um objeto de lista, com o benefício adicional de ter uma length
propriedade compatível com OOP .
Como sempre, sua milhagem pode variar.
length = property(len)
e pular a função de wrapper de uma linha e manter a documentação / introspecção de len
sua propriedade.
Além disso, len
você também pode usar operator.length_hint
(requer Python 3.4+). Para um normal, list
ambos são equivalentes, mas length_hint
possibilitam obter o comprimento de um iterador de lista, o que pode ser útil em determinadas circunstâncias:
>>> from operator import length_hint
>>> l = ["apple", "orange", "banana"]
>>> len(l)
3
>>> length_hint(l)
3
>>> list_iterator = iter(l)
>>> len(list_iterator)
TypeError: object of type 'list_iterator' has no len()
>>> length_hint(list_iterator)
3
Mas, length_hint
por definição, é apenas uma "dica", então na maioria das vezes len
é melhor.
Eu já vi várias respostas sugerindo acessar __len__
. Está tudo bem ao lidar com classes internas como list
, mas pode levar a problemas com classes personalizadas, porque len
(e length_hint
) implementam algumas verificações de segurança. Por exemplo, ambos não permitem comprimentos negativos ou comprimentos que excedam um determinado valor (o sys.maxsize
valor). Portanto, é sempre mais seguro usar a len
função em vez do __len__
método!
Respondendo à sua pergunta como os exemplos também foram fornecidos anteriormente:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
print items.__len__()
__foo__
.: isso é apenas uma convenção, uma maneira de o sistema Python usar nomes que não entrem em conflito com os nomes de usuário. 2 _foo
.: esta é apenas uma convenção, uma maneira do programador indicar que a variável é privada (o que quer que isso signifique em Python). 3 __foo
.: isso tem um significado real: o intérprete substitui esse nome _classname__foo
por uma maneira de garantir que o nome não se sobreponha a um nome semelhante em outra classe. * Nenhuma outra forma de sublinhado tem significado no mundo Python. * Não há diferença entre classe, variável, global, etc. nessas convenções.
E para completude (principalmente educacional), é possível sem o uso da len()
função. Eu não aceitaria isso como uma boa opção NÃO PROGRAMA COMO ESTE NO PYTHON , mas serve a um propósito para o aprendizado de algoritmos.
def count(list):
item_count = 0
for item in list[:]:
item_count += 1
return item_count
count([1,2,3,4,5])
(O sinal de dois pontos list[:]
está implícito e, portanto, também é opcional.)
A lição aqui para novos programadores é: Você não pode obter o número de itens em uma lista sem contá-los em algum momento. A questão é: quando é um bom momento para contá-los? Por exemplo, código de alto desempenho, como a chamada do sistema de conexão de soquetes (escrita em C) connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
, não calcula o comprimento dos elementos (atribuindo essa responsabilidade ao código de chamada). Observe que o comprimento do endereço é passado adiante para salvar a etapa de contar o comprimento primeiro? Outra opção: computacionalmente, pode fazer sentido acompanhar o número de itens à medida que você os adiciona ao objeto que você passa. Lembre-se de que isso ocupa mais espaço na memória. Veja a resposta de Naftuli Kay .
Exemplo de como acompanhar o comprimento para melhorar o desempenho e ocupar mais espaço na memória. Observe que eu nunca uso a função len () porque o comprimento é rastreado:
class MyList(object):
def __init__(self):
self._data = []
self.length = 0 # length tracker that takes up memory but makes length op O(1) time
# the implicit iterator in a list class
def __iter__(self):
for elem in self._data:
yield elem
def add(self, elem):
self._data.append(elem)
self.length += 1
def remove(self, elem):
self._data.remove(elem)
self.length -= 1
mylist = MyList()
mylist.add(1)
mylist.add(2)
mylist.add(3)
print(mylist.length) # 3
mylist.remove(3)
print(mylist.length) # 2
for item in list[:]:
? Por que não for item in list:
? Além disso, eu usaria += 1
para incrementar.
Em termos de como len()
realmente funciona, esta é sua implementação em C :
static PyObject *
builtin_len(PyObject *module, PyObject *obj)
/*[clinic end generated code: output=fa7a270d314dfb6c input=bc55598da9e9c9b5]*/
{
Py_ssize_t res;
res = PyObject_Size(obj);
if (res < 0) {
assert(PyErr_Occurred());
return NULL;
}
return PyLong_FromSsize_t(res);
}
Py_ssize_t
é o comprimento máximo que o objeto pode ter. PyObject_Size()
é uma função que retorna o tamanho de um objeto. Se não puder determinar o tamanho de um objeto, ele retornará -1. Nesse caso, este bloco de código será executado:
if (res < 0) {
assert(PyErr_Occurred());
return NULL;
}
E uma exceção é gerada como resultado. Caso contrário, este bloco de código será executado:
return PyLong_FromSsize_t(res);
res
que é um C
número inteiro, é convertido em python long
e retornado. Todos os números inteiros do python são armazenados como longs
desde o Python 3.