#python #r #list #function #methods
Вопрос:
В Python нет функции для аргумента индекса списка в __getitem()__
, __setitem()__
, __delitem()__
. Поскольку я долгое время был пользователем R, использование индекса списка выглядит вполне естественным. Я знаю, что есть pandas
или numpy
, но менять тип громоздко. И ДЛЯ ЭТОГО НУЖЕН ДОПОЛНИТЕЛЬНЫЙ ПАКЕТ!
>>> import numpy as np
>>> lst = [1,2,3,4,5]
>>> np.array(lst)[[0,3,4]]
array([1, 4, 5])
Вот мое предложение.
class list2(__builtins__.list):
def __getitem__(self, x):
if isinstance(x, __builtins__.list):
#print(x)
return [__builtins__.list.__getitem__(self, y) for y in x]
else:
return __builtins__.list.__getitem__(self,x)
def __setitem__(self, index, elem):
if isinstance(index, __builtins__.list):
if isinstance(elem, __builtins__.list):
for i,x in zip(index, elem):
__builtins__.list.__setitem__(self, i, x)
else:
for i in index:
__builtins__.list.__setitem__(self, i, elem)
#self[i] = x
else:
__builtins__.list.__setitem__(self, index, elem)
def __delitem__(self, index):
if isinstance(index, __builtins__.list):
for i in sorted(index, reverse = True):
__builtins__.list.__delitem__(self, i)
#self[i] = x
else:
__builtins__.list.__delitem__(self, index)
Кажется, это работает нормально.
>>> l = list2(['a', 'b', 'c', 'd', 'e'])
>>> l[[2,3]]
['c', 'd']
>>> l[[2,3]]= ['-', '-']
>>> l
['a', 'b', '-', '-', 'e']
>>> del l[[0,3]]
>>> l
['b', '-', 'e']
Но есть ли какая-нибудь ловушка? или есть какая-то часть, которую необходимо улучшить?
Ответ №1:
Основная загвоздка с чем — то подобным заключается в том, что это «удивительно», что обычно не одобряется в Python-мы ожидаем, что список по умолчанию будет вести себя как список по умолчанию.
Кроме того, ваша реализация в основном выглядит завершенной для меня. Возможно, есть пара проблем:
- Что произойдет, если мы используем
__setitem__
или__delitem__
и перечислим один и тот же индекс более одного раза? - Что произойдет, если мы приведем
__setitem__
списки с несоответствующей длиной?
Есть одна ключевая вещь, которую, я думаю, стоило бы изменить: избавьтесь от списков индексов и вместо этого используйте кортежи.
Если вы передадите разделенный запятыми список индексов __getitem__
, они фактически будут проанализированы как кортеж!
>>> class Thing:
... def __getitem__(self, indices):
... print(indices)
...
>>> t = Thing()
>>> t[1, 2, 3]
(1, 2, 3)
Поэтому вместо того, чтобы использовать списки, ожидайте кортежей и избавьтесь от двойных скобок.
С точки зрения других улучшений, вероятно , лучше избавиться от ссылок __builtins__
и использовать super()
для доступа к функциям из реализации списка по умолчанию, и рекомендуется добавить пользовательский __repr__
, чтобы мы не путали это со списком по умолчанию.
Если вы добавите все эти предложения, это будет выглядеть примерно так (ввод добавлен для ясности):
from typing import Any, Tuple, Union
class list2(list):
def __getitem__(self, index: Union[int, Tuple[int], slice]) -> Any:
if isinstance(index, (slice, int)):
return super().__getitem__(index)
return [super(list2, self).__getitem__(x) for x in index]
def __setitem__(self, index: Union[int, Tuple[int], slice], elem: Any):
if isinstance(index, (slice, int)):
return super().__setitem__(index, elem)
if len(index) != len(elem):
raise ValueError("Number of elements in index does not match element.")
for x, element in zip(index, elem):
self[x] = element
def __delitem__(self, index: Union[int, Tuple[int], slice]):
if isinstance(index, (slice, int)):
return super().__delitem__(index)
for x in sorted(set(index), reverse=True):
super().__delitem__(x)
def __repr__(self) -> str:
return f"list2({super().__repr__()})"
Комментарии:
1. Примечание: Это все равно будет работать , например
l[[1, 2, 3]]
, это просто больше не нужно:l[1, 2, 3]
приведет к тому же результату.2. Отличный ответ! Одна из причин, по которой я выбрал
__builtins__.list
, заключается в том, что я изменил определениеlist
на что-то вродеdef list(*args): if len(args) > 1: return [*args] else: __builtins__.list(args[0])
. В любом случае, кажется, что нет никакого способа ссылаться на роднойlist
, что бы пользователь ни сделал с окружающей средой.__builtins__.list
может быть легко назначен на другую функцию.