Rozważ następujące:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
# FAKE METHOD:
items.amount() # Should return 3
Jak uzyskać liczbę elementów na liście items
?
Rozważ następujące:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
# FAKE METHOD:
items.amount() # Should return 3
Jak uzyskać liczbę elementów na liście items
?
Odpowiedzi:
Jak uzyskać rozmiar listy?
Aby znaleźć rozmiar listy, użyj wbudowanej funkcji len
:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
I teraz:
len(items)
zwraca 3.
Wszystko w Pythonie jest obiektem, w tym listami. Wszystkie obiekty mają jakiś nagłówek w implementacji C.
W szczególności listy i inne podobne wbudowane obiekty o „rozmiarze” w Pythonie mają wywołany atrybut ob_size
, w którym buforowana jest liczba elementów w obiekcie. Sprawdzanie liczby obiektów na liście jest więc bardzo szybkie.
Ale jeśli sprawdzasz, czy rozmiar listy wynosi zero, czy nie, nie używaj len
- zamiast tego umieść listę w kontekście boolowskim - traktowana jest ona jako False, jeśli jest pusta, w przeciwnym razie True .
len(s)
Zwraca długość (liczbę elementów) obiektu. Argumentem może być sekwencja (taka jak ciąg, bajty, krotka, lista lub zakres) lub kolekcja (taka jak słownik, zestaw lub zestaw zamrożony).
len
jest implementowany z __len__
, z dokumentów modelu danych :
object.__len__(self)
Wywoływany w celu wdrożenia wbudowanej funkcji
len()
. Powinna zwracać długość obiektu, liczba całkowita> = 0. Również obiekt, który nie definiuje metody__nonzero__()
[w Python 2 lub__bool__()
Python 3] i którego__len__()
metoda zwraca zero, jest uważany za fałszywy w kontekście logicznym.
Widzimy też, że __len__
jest to metoda list:
items.__len__()
zwraca 3.
len
(długość)W rzeczywistości widzimy, że możemy uzyskać te informacje dla wszystkich opisanych typów:
>>> all(hasattr(cls, '__len__') for cls in (str, bytes, tuple, list,
xrange, dict, set, frozenset))
True
len
do testowania pustej lub niepustej listyAby przetestować określoną długość, po prostu przetestuj równość:
if len(items) == required_length:
...
Ale jest specjalny przypadek do testowania listy zerowej lub odwrotnej. W takim przypadku nie testuj równości.
Nie rób też:
if len(items):
...
Zamiast tego po prostu wykonaj:
if items: # Then we have some items, not empty!
...
lub
if not items: # Then we have an empty list!
...
I tu wyjaśnienie dlaczego , ale w skrócie, if items
czy if not items
jest zarówno bardziej czytelne i bardziej wydajnych.
Chociaż może to nie być przydatne ze względu na fakt, że miałoby o wiele większy sens jako funkcjonalność „po wyjęciu z pudełka”, dość prostym hackem byłoby zbudowanie klasy z length
właściwością:
class slist(list):
@property
def length(self):
return len(self)
Możesz go używać w następujący sposób:
>>> l = slist(range(10))
>>> l.length
10
>>> print l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Zasadniczo jest dokładnie identyczny z obiektem listy, z dodatkową zaletą posiadania length
właściwości przyjaznej dla OOP .
Jak zawsze przebieg może się różnić.
length = property(len)
pominąć funkcję owijania jednego wiersza i zachować dokumentację / introspekcję len
swojej właściwości.
Poza tym len
możesz także używać operator.length_hint
(wymaga Python 3.4+). Dla normalnego list
oba są równoważne, ale length_hint
umożliwia uzyskanie długości iteratora listy, co może być przydatne w pewnych okolicznościach:
>>> 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
Ale length_hint
z definicji jest tylko „wskazówką”, więc przez większość czasu len
jest lepiej.
Widziałem kilka odpowiedzi sugerujących dostęp __len__
. Jest to w porządku, gdy mamy do czynienia z wbudowanymi klasami takimi jak list
, ale może to prowadzić do problemów z klasami niestandardowymi, ponieważ len
(i length_hint
) wdrażają pewne kontrole bezpieczeństwa. Na przykład oba nie zezwalają na ujemne długości lub długości, które przekraczają określoną wartość ( sys.maxsize
wartość). Dlatego zawsze bezpieczniej jest używać len
funkcji zamiast __len__
metody!
Odpowiadając na twoje pytanie jako przykłady podane wcześniej:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
print items.__len__()
__foo__
.: to tylko konwencja, sposób, w jaki system Python może używać nazw, które nie będą powodować konfliktów z nazwami użytkowników. 2 _foo
.: to tylko konwencja, sposób dla programisty na wskazanie, że zmienna jest prywatna (cokolwiek to znaczy w Pythonie). 3 __foo
.: to ma prawdziwe znaczenie: interpreter zastępuje tę nazwę _classname__foo
jako sposób, aby nazwa nie nakładała się na podobną nazwę w innej klasie. * Żadna inna forma podkreślenia nie ma znaczenia w świecie Python. * W tych konwencjach nie ma różnicy między klasą, zmienną, globalną itp.
A dla kompletności (przede wszystkim edukacyjnej) jest to możliwe bez użycia len()
funkcji. Nie przyjąłbym tego za dobrą opcję. NIE PROGRAMUJ JAK TEGO W PYTHONIE , ale służy to celowi uczenia się algorytmów.
def count(list):
item_count = 0
for item in list[:]:
item_count += 1
return item_count
count([1,2,3,4,5])
(Dwukropek w list[:]
jest ukryty i dlatego jest również opcjonalny.)
Lekcja dla nowych programistów brzmi: nie można uzyskać liczby pozycji na liście, nie licząc ich w pewnym momencie. Powstaje pytanie: kiedy należy je policzyć? Na przykład kod o wysokiej wydajności, taki jak wywołanie systemowe Connect dla gniazd (napisane w C) connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
, nie oblicza długości elementów (przypisując odpowiedzialność za kod wywołujący). Zauważ, że długość adresu jest przekazywana, aby zapisać krok liczenia długości jako pierwszy? Inna opcja: obliczeniowo sensowne może być śledzenie liczby elementów podczas dodawania ich w przekazywanym obiekcie. Pamiętaj, że zajmuje to więcej miejsca w pamięci. Zobacz odpowiedź Naftuli Kay .
Przykład śledzenia długości w celu poprawy wydajności przy jednoczesnym zajmowaniu większej ilości miejsca w pamięci. Zauważ, że nigdy nie używam funkcji len (), ponieważ długość jest śledzona:
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[:]:
? Dlaczego nie for item in list:
? Chciałbym += 1
również zwiększyć.
Pod względem tego, jak len()
faktycznie działa, jest to jego implementacja 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
to maksymalna długość, jaką może mieć obiekt. PyObject_Size()
to funkcja zwracająca rozmiar obiektu. Jeśli nie może określić rozmiaru obiektu, zwraca -1. W takim przypadku ten blok kodu zostanie wykonany:
if (res < 0) {
assert(PyErr_Occurred());
return NULL;
}
W rezultacie powstaje wyjątek. W przeciwnym razie ten blok kodu zostanie wykonany:
return PyLong_FromSsize_t(res);
res
która jest C
liczbą całkowitą, jest konwertowana na python long
i zwracana. Wszystkie liczby całkowite w Pythonie są przechowywane od longs
czasu wydania Python 3.