Розглянемо наступне:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
# FAKE METHOD:
items.amount() # Should return 3
Як отримати кількість елементів у списку items
?
Розглянемо наступне:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
# FAKE METHOD:
items.amount() # Should return 3
Як отримати кількість елементів у списку items
?
Відповіді:
Як отримати розмір списку?
Щоб знайти розмір списку, використовуйте вбудовану функцію len
:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
І зараз:
len(items)
повертає 3.
Все в Python є об'єктом, включаючи списки. У всіх об'єктах є заголовок певного типу в реалізації C.
Списки та інші подібні вбудовані об'єкти з "розміром" у Python, зокрема, мають атрибут, який називається ob_size
, де кількість елементів у об'єкті кешовано. Тож перевірка кількості об’єктів у списку відбувається дуже швидко.
Але якщо ви перевіряєте, чи розмір списку дорівнює нулю чи ні, не використовуйте len
- замість цього ставте список у бульовому контексті - він трактується як Неправильний, якщо порожній, Істинно інакше .
len(s)
Поверніть довжину (кількість елементів) об'єкта. Аргументом може бути послідовність (наприклад, рядок, байти, кортеж, список або діапазон) або колекція (наприклад, словник, набір або заморожений набір).
len
реалізується з документами__len__
моделі даних :
object.__len__(self)
Викликається реалізувати вбудовану функцію
len()
. Потрібно повернути довжину об'єкта, ціле число> = 0. Також об'єкт, який не визначає метод__nonzero__()
[у Python 2 або__bool__()
Python 3] і__len__()
метод якого повертає нуль, вважається помилковим у булевому контексті.
І ми також можемо побачити, що __len__
це метод списків:
items.__len__()
повертає 3.
len
(довжина)І насправді ми бачимо, що ми можемо отримати цю інформацію для всіх описаних типів:
>>> all(hasattr(cls, '__len__') for cls in (str, bytes, tuple, list,
xrange, dict, set, frozenset))
True
len
для тестування порожнього чи непорожнього спискуДля тестування на певну довжину, звичайно, просто перевіряйте рівність:
if len(items) == required_length:
...
Але є особливий випадок для тестування списку нульової довжини або зворотного. У цьому випадку не перевіряйте рівність.
Також не робіть:
if len(items):
...
Замість цього просто зробіть:
if items: # Then we have some items, not empty!
...
або
if not items: # Then we have an empty list!
...
Я пояснюю, чому тут, але коротше, if items
або він if not items
є і читабельнішим, і ефективнішим.
Хоча це може бути не корисним через те, що це мало б набагато більшого сенсу, як функція "поза коробкою", досить простим хаком було б створити клас із length
властивістю:
class slist(list):
@property
def length(self):
return len(self)
Ви можете використовувати його так:
>>> l = slist(range(10))
>>> l.length
10
>>> print l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
По суті, він абсолютно ідентичний об'єкту списку, з додатковою перевагою мати length
властивість, сприятливу для OOP .
Як завжди, пробіг може відрізнятися.
length = property(len)
та пропустити функцію обгортки з однієї лінії та зберегти документацію / самоаналіз len
свого майна.
Крім того, len
ви також можете використовувати operator.length_hint
(потрібен Python 3.4+). Для нормального list
обидва є рівнозначними, але length_hint
дає можливість отримати довжину списку-ітератора, який може бути корисним за певних обставин:
>>> 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
Але length_hint
це за визначенням лише "натяк", тому більшу частину часу len
краще.
Я бачив кілька відповідей, які пропонують отримати доступ __len__
. Це все в порядку, коли стосується вбудованих класів на кшталт list
, але це може призвести до проблем із користувацькими класами, оскільки len
(і length_hint
) проводять деякі перевірки безпеки. Наприклад, обидва не допускають негативних довжин або довжин, що перевищують певне значення ( sys.maxsize
значення). Тому завжди безпечніше використовувати len
функцію замість __len__
методу!
Відповідаючи на ваше запитання, як наведені раніше приклади:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
print items.__len__()
__foo__
.: це лише умова, спосіб для системи Python використовувати імена, які не суперечать іменам користувачів. 2 _foo
.: це лише умова, спосіб програмісту вказати, що змінна є приватною (що б це не означало в Python). 3 __foo
.: це має реальне значення: інтерпретатор замінює це ім'я _classname__foo
на спосіб переконатися, що ім'я не збігатиметься з подібним ім'ям в іншому класі. * Жодна інша форма підкреслення не має значення в світі Python. * У цих конвенціях немає різниці між класом, змінною, глобальною тощо.
А для повноти (насамперед навчальної), це можливо без використання len()
функції. Я б не погоджувався на це як на хороший варіант, НЕ ПРОГРАМУЙТЕ ТАКОЖ У ПІТОНІ , але це служить метою для вивчення алгоритмів.
def count(list):
item_count = 0
for item in list[:]:
item_count += 1
return item_count
count([1,2,3,4,5])
(Двокрапка кишки list[:]
введена неявно, тому також є необов'язковою.)
Урок для нових програмістів: Ви не можете отримати кількість елементів у списку, не рахуючи їх у якийсь момент. Постає питання: коли настав час їх порахувати? Наприклад, високопродуктивний код, як системний виклик підключення для сокетів (написаний на С) connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
, не обчислює довжину елементів (віддаючи цю відповідальність коду, що викликає). Зауважте, що довжина адреси передається разом, щоб зберегти крок підрахунку довжини спочатку? Інший варіант: обчислювально, можливо, має сенс відслідковувати кількість елементів під час додавання їх у об'єкт, який ви передаєте. Зверніть увагу, що це займає більше місця в пам'яті. Дивіться відповідь Нафтулі Кей .
Приклад відстеження довжини для підвищення продуктивності, займаючи більше місця в пам'яті. Зауважте, що я ніколи не використовую функцію len (), оскільки відстежується довжина:
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[:]:
? Чому ні for item in list:
? Крім того, я хотів би використовувати += 1
приріст.
Що стосується того, як len()
насправді працює, це його реалізація на 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
- максимальна довжина, яку може мати об’єкт. PyObject_Size()
- це функція, яка повертає розмір об'єкта. Якщо він не може визначити розмір об'єкта, він повертає -1. У цьому випадку цей код коду буде виконаний:
if (res < 0) {
assert(PyErr_Occurred());
return NULL;
}
І в результаті виникає виняток. В іншому випадку цей код коду буде виконаний:
return PyLong_FromSsize_t(res);
res
що є C
цілим числом, перетворюється в пітон long
і повертається. Всі цілі числа python зберігаються як longs
з Python 3.