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).
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.
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
lendo 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 itemsczy if not itemsjest 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 lengthwł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 lengthwł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ę lenswojej właściwości.
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!
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__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.
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 += 1ró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_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:
return PyLong_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.