Oczywiście pytasz o liczbę elementów na liście. Jeśli przychodzi tu poszukiwacz wielkości obiektu w pamięci, to właśnie tego pytania i odpowiedzi szukają: Jak określić rozmiar obiektu w Pythonie?
Aaron Hall
Odpowiedzi:
2640
Tej len()funkcji można używać z kilkoma różnymi typami w Pythonie - zarówno typami wbudowanymi, jak i typami bibliotek. Na przykład:
>>> len([1,2,3])3
Oficjalna dokumentacja 2.x jest tutaj:
Oficjalna dokumentacja 3.x jest tutaj:len() len()
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.
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).
lenjest 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.
Wbudowane typy, które możesz uzyskać len(długość)
W rzeczywistości widzimy, że możemy uzyskać te informacje dla wszystkich opisanych typów:
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 lengthwłaściwością:
class slist(list):@propertydef 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 lengthwłaściwości przyjaznej dla OOP .
tylko dlatego, że wiesz, możesz po prostu length = property(len)pominąć funkcję owijania jednego wiersza i zachować dokumentację / introspekcję lenswojej właściwości.
Tadhg McDonald-Jensen
17
Poza tym lenmożesz także używać operator.length_hint(wymaga Python 3.4+). Dla normalnego listoba są równoważne, ale length_hintumoż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_hintz definicji jest tylko „wskazówką”, więc przez większość czasu lenjest 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.maxsizewartość). Dlatego zawsze bezpieczniej jest używać lenfunkcji zamiast __len__metody!
W Pythonie nazwy rozpoczynające się od podkreślenia są semantycznie niepublicznymi metodami i nie powinny być używane przez użytkowników.
Aaron Hall
2
1 __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__foojako 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.
Shai Alon,
4
To pytanie i wyjaśnienie, dlaczego nie powinieneś używać specjalnych metod bezpośrednio jako użytkownik: stackoverflow.com/q/40272161/541136
Aaron Hall
@AaronHall, ale dla funkcji len jest prawie taki sam. Może być szybszy dla bardzo dużych zmiennych. Rozumiem jednak twój punkt widzenia i powinniśmy używać len (obj), a nie obj .__ len __ ().
Shai Alon
7
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.
(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:
classMyList(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 classdef __iter__(self):for elem in self._data:yield elem
def add(self, elem):
self._data.append(elem)
self.length +=1def 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
Dlaczego for item in list[:]:? Dlaczego nie for item in list:? Chciałbym += 1również zwiększyć.
Babcia Boli
@GrannyAching wyraźnie wspomniałem o opcjonalnym dwukropku (specyfikator zakresu). Zostawiłem tam specyfikator zasięgu do celów edukacyjnych - warto wiedzieć, że jest to implikowane. Typ listy [] jest również wywnioskowany, jak sugerujesz, jako odpowiednik mojego kodu. Operator inkrementacji jest również równoważny z dodaniem 1 do istniejącej zmiennej, ale we wszystkich przypadkach jest krótszy. Zgadzam się więc, że należy tego użyć, jeśli takie jest twoje rozumowanie. Zresztą ten kod nie powinien być nigdzie produkowany (z wyjątkiem uczenia się programowania).
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;}returnPyLong_FromSsize_t(res);}
Py_ssize_tto 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:
returnPyLong_FromSsize_t(res);
resktóra jest Cliczbą całkowitą, jest konwertowana na python longi zwracana. Wszystkie liczby całkowite w Pythonie są przechowywane od longsczasu wydania Python 3.
Odpowiedzi:
Tej
len()
funkcji można używać z kilkoma różnymi typami w Pythonie - zarówno typami wbudowanymi, jak i typami bibliotek. Na przykład:Oficjalna dokumentacja 2.x jest tutaj: Oficjalna dokumentacja 3.x jest tutaj:
len()
len()
źródło
Aby znaleźć rozmiar listy, użyj wbudowanej funkcji
len
:I teraz:
zwraca 3.
Wyjaśnienie
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 .Z dokumentów
len(s)
len
jest implementowany z__len__
, z dokumentów modelu danych :object.__len__(self)
Widzimy też, że
__len__
jest to metoda list:zwraca 3.
Wbudowane typy, które możesz uzyskać
len
(długość)W rzeczywistości widzimy, że możemy uzyskać te informacje dla wszystkich opisanych typów:
Nie należy używać
len
do testowania pustej lub niepustej listyAby przetestować określoną długość, po prostu przetestuj równość:
Ale jest specjalny przypadek do testowania listy zerowej lub odwrotnej. W takim przypadku nie testuj równości.
Nie rób też:
Zamiast tego po prostu wykonaj:
lub
I tu wyjaśnienie dlaczego , ale w skrócie,
if items
czyif not items
jest zarówno bardziej czytelne i bardziej wydajnych.źródło
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ą:Możesz go używać w następujący sposób:
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ć.
źródło
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 normalnegolist
oba są równoważne, alelength_hint
umożliwia uzyskanie długości iteratora listy, co może być przydatne w pewnych okolicznościach:Ale
length_hint
z definicji jest tylko „wskazówką”, więc przez większość czasulen
jest lepiej.Widziałem kilka odpowiedzi sugerujących dostęp
__len__
. Jest to w porządku, gdy mamy do czynienia z wbudowanymi klasami takimi jaklist
, ale może to prowadzić do problemów z klasami niestandardowymi, ponieważlen
(ilength_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!źródło
Odpowiadając na twoje pytanie jako przykłady podane wcześniej:
źródło
__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.(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:
źródło
for item in list[:]:
? Dlaczego niefor item in list:
? Chciałbym+= 1
również zwiększyć.Pod względem tego, jak
len()
faktycznie działa, jest to jego implementacja C :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:W rezultacie powstaje wyjątek. W przeciwnym razie ten blok kodu zostanie wykonany:
res
która jestC
liczbą całkowitą, jest konwertowana na pythonlong
i zwracana. Wszystkie liczby całkowite w Pythonie są przechowywane odlongs
czasu wydania Python 3.źródło