我想将一些元数据包含到python切片对象中,同时添加变量以指示切片中每个元素的索引。元数据用于标记切片正在检索的每个元素。我知道可以使用其他标记的数据结构,但在我的项目中,切片被预定义为numpy数组的一种下标,并在各个地方重复使用。所以,对我来说,找到一种方法来加入它是有道理的。
我在考虑对slice
进行分类,但显然它不能是subclassed,这在链接问题的答案中已经清楚地解释了。从那时起有什么变化吗?
我想要做的是创建一个类似于以下的类:
class Subscript:
def __init__(self, start, stop, step=None, labels=None):
self.labels = labels
self.slc = slice(start, stop, step)
for i, l in zip(range(start, stop, step), labels):
setattr(self, l, i)
并能够像这样使用它:
sub = Subscript(0, 5, labels=['s0', 's1', 's2', 's3', 's4'])
list(range(10))[sub] # [0, 1, 2, 3, 4]
range(10)[sub.s0] # 0
有没有办法在不必添加__call__
方法返回切片的情况下执行此操作?不知怎的,我怀疑这是因为sub
到__getitem__
的数组或列表不知道如何处理这个问题。我知道我可能只是将这些信息修补到slice
,但我想知道这类事情是否可以在课堂上完成。
目前,我正在分别定义切片和切片元素,如:
sub = slice(0, 5)
s0, s1, s2, s3, s4 = range(5)
但是这种方法使得将多维数组的输出处理成dict变得更加困难,其中在多于1 sub
的情况下键是下标元素组合,并且值是1d数组。
答案 0 :(得分:1)
不,slice
个对象仍然不能被分类。我在默认的Python(PySlice_Type
)分支中为3.7
定义了基于on the flags的内容:
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
要允许对象充当基类,相应的Py_TPFLAGS_BASETYPE
将or
在那里,因为它们具有允许的类型。以lists为例,他们的标志定义为:
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE | Py_TPFLAGS_LIST_SUBCLASS, /* tp_flags */
忽略其余部分,Py_TPFLAGS_BASETYPE
在其中|
允许其作为基类。
由于我无法在文档的某个地方找到这个提及的事实,我说它是一个实现细节,其理由我目前都不知道。我相信你可能绕过它的唯一方法就是放到C
并在那里上课。
答案 1 :(得分:1)
我最终做的是子类numpy.ndarray
因为我只是试图将切片传递给这种类型的对象(可以对列表执行相同的操作),然后重新实现__getitem__
以便如果传入Subscript
对象然后在传递给父方法之前首先提取切片。
看起来像:
import numpy as np
class SubArray(np.ndarray):
def __new__(cls, input_array, subs=None):
obj = np.asarray(input_array).view(cls)
obj.subs = subs
return obj
def __getitem__(self, *args):
args = tuple([a.slc if isinstance(a, SubRange) else a for a in args])
return super().__getitem__(*args)
def __array_finalize__(self, obj):
if obj is None:
return
self.subs = getattr(obj, 'subs', None)
class Subscript:
def __init__(self, labels, bounds=None):
name, elements = labels
if bounds:
start, stop = bounds
else:
start, stop = 0, len(elements)
self.size = stop - start
self.slc = slice(start, stop)
self.labels = labels
self.name = name
self.elements = elements
for l, i in zip(labels, range(start, stop)):
setattr(self, l, i)
可以这样使用:
sub = Subscript(('sub', ['s0', 's1', 's2', 's3', 's4']))
SubArray(np.arange(10), subs=sub)[sub] # SubArray([0, 1, 2, 3, 4])
SubArray(np.arange(10), subs=sub)[sub.s0] # 0
这更接近于我所避免的方法(即使用像xarray这样的方法),但结果仍然基本上是一个numpy数组,对我有用。