Como obtenho o número de elementos em uma lista?

1938

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?

y2k
fonte
23
Você está obviamente pedindo o número de elementos na lista. Se um pesquisador chegar aqui procurando o tamanho do objeto na memória, esta é a pergunta e as respostas reais que ele está procurando: Como determinar o tamanho de um objeto no Python?
Aaron Hall

Respostas:

2640

A len()função pode ser usada com vários tipos diferentes em Python - tipos internos e tipos de biblioteca. Por exemplo:

>>> len([1,2,3])
3

A documentação oficial 2.x está aqui: A documentação oficial 3.x está aqui:len()
len()

gnud
fonte
239

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.

Explicação

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 .

Dos documentos

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.

Tipos internos você pode obter o len(comprimento) de

De 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

Não use lenpara testar uma lista vazia ou não vazia

Para 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 itemsou if not itemsé mais legível e com melhor desempenho.

Aaron Hall
fonte
75

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 lengthpropriedade:

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 lengthpropriedade compatível com OOP .

Como sempre, sua milhagem pode variar.

Naftuli Kay
fonte
19
só para você saber, você pode simplesmente fazer length = property(len)e pular a função de wrapper de uma linha e manter a documentação / introspecção de lensua propriedade.
Tadhg McDonald-Jensen
17

Além disso, lenvocê também pode usar operator.length_hint(requer Python 3.4+). Para um normal, listambos são equivalentes, mas length_hintpossibilitam 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_hintpor 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.maxsizevalor). Portanto, é sempre mais seguro usar a lenfunção em vez do __len__método!

MSeifert
fonte
8

Respondendo à sua pergunta como os exemplos também foram fornecidos anteriormente:

items = []
items.append("apple")
items.append("orange")
items.append("banana")

print items.__len__()
Shai Alon
fonte
15
No Python, os nomes que começam com sublinhados são métodos semanticamente não públicos e não devem ser usados ​​pelos usuários.
Aaron Hall
2
1 __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__foopor 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.
Shai Alon
4
Esta sessão de perguntas e respostas explica por que você não deve usar os métodos especiais diretamente como usuário: stackoverflow.com/q/40272161/541136
Aaron Hall
@ AaronHall, mas para a função len é quase o mesmo. Pode ser mais rápido para variáveis ​​muito grandes. No entanto, entendi seu argumento e devemos usar len (obj) e não obj .__ len __ ().
Shai Alon
7

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
Jonathan Komar
fonte
Por que for item in list[:]:? Por que não for item in list:? Além disso, eu usaria += 1para incrementar.
Granny Aching
@GrannyAching Mencionei explicitamente os dois pontos opcionais (especificador de intervalo). Deixei o especificador de intervalo lá para fins educacionais - é benéfico saber que está implícito. Um tipo de lista [] também é inferido, como você sugere - equivalente ao meu código. O operador de incremento também é equivalente a adicionar 1 a uma variável existente, ainda mais curta em todos os casos. Então, eu concordo que deve ser usado se esse for o seu raciocínio. De qualquer forma, esse código não deve ser colocado em produção em nenhum lugar (exceto ao aprender programação).
Jonathan Komar
0

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);

resque é um Cnúmero inteiro, é convertido em python longe retornado. Todos os números inteiros do python são armazenados como longsdesde o Python 3.

Alec Alameddine
fonte
3
Por que saber ou saber sobre a implementação C é importante?
cs95
Como essa pergunta não é específica para o CPython, essa resposta pode ser enganosa. PyPy, IronPython, ... podem e implementam de maneira diferente.
MSDIFER #