Considera quanto segue:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
# FAKE METHOD:
items.amount() # Should return 3
Come posso ottenere il numero di elementi nell'elenco items
?
Considera quanto segue:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
# FAKE METHOD:
items.amount() # Should return 3
Come posso ottenere il numero di elementi nell'elenco items
?
Risposte:
Come ottenere le dimensioni di un elenco?
Per trovare le dimensioni di un elenco, utilizzare la funzione built-in, len
:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
E adesso:
len(items)
ritorna 3.
Tutto in Python è un oggetto, compresi gli elenchi. Tutti gli oggetti hanno un'intestazione di qualche tipo nell'implementazione C.
Gli elenchi e altri oggetti incorporati simili con una "dimensione" in Python, in particolare, hanno un attributo chiamato ob_size
, in cui viene memorizzato nella cache il numero di elementi nell'oggetto. Quindi controllare il numero di oggetti in un elenco è molto veloce.
Ma se stai controllando se la dimensione dell'elenco è zero o no, non usare len
- invece, metti l'elenco in un contesto booleano - trattato come False se vuoto, True altrimenti .
len(s)
Restituisce la lunghezza (il numero di elementi) di un oggetto. L'argomento può essere una sequenza (come una stringa, byte, tupla, elenco o intervallo) o una raccolta (come un dizionario, un insieme o un insieme congelato).
len
è implementato con __len__
, dai documenti del modello dati :
object.__len__(self)
Chiamato per implementare la funzione integrata
len()
. Dovrebbe restituire la lunghezza dell'oggetto, un numero intero> = 0. Inoltre, un oggetto che non definisce un metodo__nonzero__()
[in Python 2 o__bool__()
in Python 3] e il cui__len__()
metodo restituisce zero è considerato falso in un contesto booleano.
E possiamo anche vedere che __len__
è un metodo di elenchi:
items.__len__()
ritorna 3.
len
(lunghezza)E infatti vediamo che possiamo ottenere queste informazioni per tutti i tipi descritti:
>>> all(hasattr(cls, '__len__') for cls in (str, bytes, tuple, list,
xrange, dict, set, frozenset))
True
len
per verificare un elenco vuoto o non vuotoPer testare una lunghezza specifica, ovviamente, è sufficiente verificare l'uguaglianza:
if len(items) == required_length:
...
Ma c'è un caso speciale per i test per un elenco di lunghezza zero o l'inverso. In tal caso, non testare l'uguaglianza.
Inoltre, non fare:
if len(items):
...
Invece, fai semplicemente:
if items: # Then we have some items, not empty!
...
o
if not items: # Then we have an empty list!
...
Mi spiego perché qui , ma insomma, if items
o if not items
sia più leggibile e più performante.
Mentre questo potrebbe non essere utile a causa del fatto che avrebbe molto più senso come funzionalità "out of the box", un trucco abbastanza semplice sarebbe quello di costruire una classe con una length
proprietà:
class slist(list):
@property
def length(self):
return len(self)
Puoi usarlo così:
>>> l = slist(range(10))
>>> l.length
10
>>> print l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In sostanza, è esattamente identico a un oggetto elenco, con l'ulteriore vantaggio di avere una length
proprietà compatibile con OOP .
Come sempre, il tuo chilometraggio può variare.
length = property(len)
e saltare la funzione wrapper a una riga e conservare la documentazione / introspezione len
con la tua proprietà.
Inoltre len
puoi anche usare operator.length_hint
(richiede Python 3.4+). Per un normale list
entrambi sono equivalenti, ma length_hint
rende possibile ottenere la lunghezza di un elenco-iteratore, che potrebbe essere utile in determinate circostanze:
>>> 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
Ma length_hint
è per definizione solo un "suggerimento", quindi il più delle volte len
è meglio.
Ho visto diverse risposte che suggeriscono l'accesso __len__
. Questo va bene quando si tratta di classi integrate come list
, ma potrebbe portare a problemi con le classi personalizzate, perché len
(e length_hint
) implementare alcuni controlli di sicurezza. Ad esempio, entrambi non consentono lunghezze o lunghezze negative che superano un determinato valore (il sys.maxsize
valore). Quindi è sempre più sicuro usare la len
funzione invece del __len__
metodo!
Rispondere alla tua domanda come gli esempi forniti anche in precedenza:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
print items.__len__()
__foo__
.: questa è solo una convenzione, un modo per il sistema Python di usare nomi che non entreranno in conflitto con i nomi degli utenti. 2 _foo
.: questa è solo una convenzione, un modo per il programmatore di indicare che la variabile è privata (qualunque cosa ciò significhi in Python). 3 __foo
.: questo ha un significato reale: l'interprete sostituisce questo nome con _classname__foo
un modo per assicurarsi che il nome non si sovrapponga a un nome simile in un'altra classe. * Nessun'altra forma di trattini bassi ha significato nel mondo Python. * Non c'è alcuna differenza tra classe, variabile, globale, ecc. In queste convenzioni.
E per completezza (principalmente educativa), è possibile senza usare la len()
funzione. Non lo perdonerei come una buona opzione NON PROGRAMMARE COME QUESTO IN PYTHON , ma serve a uno scopo di apprendimento degli algoritmi.
def count(list):
item_count = 0
for item in list[:]:
item_count += 1
return item_count
count([1,2,3,4,5])
(Il colon in list[:]
è implicito ed è quindi anche facoltativo.)
La lezione qui per i nuovi programmatori è: non è possibile ottenere il numero di elementi in un elenco senza contarli ad un certo punto. La domanda diventa: quando è il momento giusto per contarli? Ad esempio, un codice ad alte prestazioni come la chiamata del sistema connect per socket (scritto in C) connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
, non calcola la lunghezza degli elementi (attribuendo tale responsabilità al codice chiamante). Notare che la lunghezza dell'indirizzo viene passata per salvare il passaggio del conteggio della lunghezza prima? Un'altra opzione: dal punto di vista computazionale, potrebbe avere senso tenere traccia del numero di elementi mentre li aggiungi all'interno dell'oggetto che passi. Ricorda che questo occupa più spazio nella memoria. Vedi la risposta di Naftuli Kay .
Esempio di monitoraggio della lunghezza per migliorare le prestazioni occupando più spazio in memoria. Nota che non utilizzo mai la funzione len () perché viene tracciata la lunghezza:
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[:]:
? Perché no for item in list:
? Inoltre, userei += 1
per incrementare.
In termini di come len()
funziona effettivamente, questa è la sua implementazione in 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
è la lunghezza massima che l'oggetto può avere. PyObject_Size()
è una funzione che restituisce la dimensione di un oggetto. Se non è in grado di determinare la dimensione di un oggetto, restituisce -1. In tal caso, questo blocco di codice verrà eseguito:
if (res < 0) {
assert(PyErr_Occurred());
return NULL;
}
E di conseguenza viene sollevata un'eccezione. Altrimenti, questo blocco di codice verrà eseguito:
return PyLong_FromSsize_t(res);
res
che è un C
numero intero, viene convertito in un pitone long
e restituito. Tutti i numeri interi di Python sono memorizzati come longs
da Python 3.