Я создаю контейнерный класс на Python, который либо наследуется от list
, либо просто реализует все стандартные методы списка (мне все равно, какие именно).
Как мне создать метод, который будет воздействовать только на элементы, возвращаемые из среза? Мне удалось создать метод, который будет воздействовать на весь контейнер (см. ниже), но я не могу понять, как воздействовать только на срез.
Я использую python 2.7.6 и использую from __future__ import print_function, division
во всем своем коде.
Пример кода:
from __future__ import print_function, division
import itertools
class MyContainerClass(list):
""" For now, I'm inheriting from list. Is this my problem? """
def __init__(self, data_array):
list.__init__(self, data_array)
def __getitem__(self, *args):
arg = args[0]
# specific indices MyContainerClass[0, 3, 5] => indexes 0, 3, and 5
if isinstance(arg, (list, tuple)) and not isinstance(arg[0], bool):
return [list.__getitem__(self, _i) for _i in arg]
# standard slice notation
elif isinstance(arg, slice):
return list.__getitem__(self, arg)
# Using an array mask MyContainerClass[[True, False, False,...,True]] => index 0 and -1]
elif isinstance(arg[0], bool): # or isinstance(arg, np.ndarray):
return list(itertools.compress(self, arg))
else:
# I'll eventually replace this with and exception raise.
return 'error'
def my_method(self):
"""
Will act on entire list, but I want it to act on only what's
returned by the slice (which may be the entire list in some cases).
"""
return "a, ".join([str(_i) for _i in self])
Вот пример использования, которое я хотел бы:
>>> data = MyContainerClass([1, 2, 3, 4, 5, 6, 7])
>>> data[5:]
[6, 7]
>>> data.my_method() # This works as expected
"1a, 2a, 3a, 4a, 5a, 6a, 7"
>>> data[0:3].my_method() # Doesn't work
"1a, 2a, 3" # but should return this
Похоже, теперь все работает. Большое спасибо, ребята! Вот что у меня получилось:
from __future__ import print_function, division
import itertools
class MyContainerClass(list):
"""
"""
def __init__(self, array):
if isinstance(array, int):
list.__init__(self, [array])
else:
list.__init__(self, array)
def __getitem__(self, arg):
# Standard Slice notation
if isinstance(arg, slice):
retval = super(MyContainerClass, self).__getitem__(arg)
# specific indices
elif isinstance(arg, (list, tuple)) and not isinstance(arg[0], bool):
retval = [list.__getitem__(self, _i) for _i in arg]
# a single specific index
elif isinstance(arg, int):
retval = list.__getitem__(self, arg)
# an array mask of T/F values
elif isinstance(arg[0], bool): # or isinstance(arg, np.ndarray):
retval = list(itertools.compress(self, arg))
# raise an error on unknown
else:
raise SyntaxError("Unknown notation for list slice or index")
retval = type(self)(retval)
return retval
def __getslice__(self, i, j):
# Python 2 built-in types only
return self.__getitem__(slice(i, j))
def my_method(self):
return "a, ".join([str(_i) for _i in self])
И действует как:
>>> data = MyContainerClass([1, 2, 3, 4, 5, 6, 7])
>>> mask = [True, True, False, True, False, False, False]
>>> print(data)
[1, 2, 3, 4, 5, 6, 7]
>>> print(type(data[5:]))
<class '__main__.MyContainerClass'>
>>> print(data.my_method())
1a, 2a, 3a, 4a, 5a, 6a, 7
>>> print(data[0:5].my_method())
1a, 2a, 3a, 4a, 5
>>> print(data[1, 5, 2].my_method())
2a, 6a, 3
>>> print(data[mask].my_method())
1a, 2a, 4
>>> print(data[2].my_method())
3
list
, то, вероятно, нет. И в этом проблема: срез — этоlist
, у которого нет этого метода. В качестве альтернативы, почему бы просто не сделать это функцией, а не методом? - person tobias_k   schedule 26.08.2014__future__ import print_function, division
. Я отредактировал сообщение, чтобы отразить это. - person dthor   schedule 26.08.2014__getitem__
выглядит сейчас? - person tobias_k   schedule 26.08.2014