【发布时间】:2014-10-20 02:38:51
【问题描述】:
我正在 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,它没有这个方法。或者,为什么不把它变成一个函数而不是一个方法呢? -
也许你会感兴趣:stackoverflow.com/a/16033058/2363712 ?
-
这是 Python 2 还是 Python 3?
-
@tobias_k:我希望切片成为该类的一个实例,是的。那应该可以解决我的问题。至于函数v法:在大项目设计中更有用的方法。你在这里看到的只是一个简化的例子:-)
-
@SylvainLeroux:我正在编写的实际类使用 getitem 以便我可以接受切片表示法、数组掩码或索引列表来返回元素。正如我在另一条评论中提到的,似乎我只需要弄清楚如何让 getitem 返回 MyContainerClass 的实例而不是列表。