我们怎样才能让一个类在适当时将自己表示为切片?
这没有用:
class MyThing(object):
def __init__(self, start, stop, otherstuff):
self.start = start
self.stop = stop
self.otherstuff = otherstuff
def __index__(self):
return slice(self.start, self.stop)
预期产出:
>>> thing = MyThing(1, 3, 'potato')
>>> 'hello world'[thing]
'el'
实际输出:
TypeError: __index__ returned non-(int,long) (type slice)
继承slice
也不起作用。
答案 0 :(得分:7)
TLDR:对于内置类型(例如slice
和list
),无法使自定义类替换tuple
。
__index__
方法纯粹是为了提供索引,根据定义它是python中的一个整数(参见the Data Model)。您无法使用它将对象解析为slice
。
我担心slice
似乎是由python专门处理的。界面需要一个实际的切片;提供其签名(也包括indices
方法)是不够的。正如您所知,您无法继承它,因此您无法创建新类型的slice
。即使Cython也不允许你继承它。
为什么slice
特别?很高兴你问。欢迎来到CPython的内部。阅读本文后请洗手。
所以切片对象在slice.rst
中描述。请注意这两个人:
.. c:var :: PyTypeObject PySlice_Type
切片对象的类型对象。这与:class:
slice
中的相同 Python层。.. c:function :: int PySlice_Check(PyObject * ob) 如果 ob 是切片对象,则返回true; ob 不得 NULL 。
现在,这实际上是在sliceobject.h
中实现的:
#define PySlice_Check(op) (Py_TYPE(op) == &PySlice_Type)
所以仅此处允许slice
类型。在尝试使用索引协议之后,此检查实际用于list_subscript
(和tuple subscript
,...)(因此片上的__index__
是一个馊主意)。自定义容器类可以自由覆盖__getitem__
并使用自己的规则,但这就是list
(和tuple
,...)的工作方式。
现在,为什么不能继承slice
?好吧,type
实际上有一个标志,指示是否可以对子类进行子类化。检查here并生成您看到的错误:
if (!PyType_HasFeature(base_i, Py_TPFLAGS_BASETYPE)) {
PyErr_Format(PyExc_TypeError,
"type '%.100s' is not an acceptable base type",
base_i->tp_name);
return NULL;
}
我无法追踪slice
(联合国)如何设置此值,但是获得此错误的事实意味着它确实如此。这意味着你不能将它子类化。
结束语:记住一些长期被遗忘的C-(非)技能后,我很确定这不是严格意义上的优化。所有现有的检查和技巧仍然有用(至少我发现的那些)。
在洗手并在互联网上挖掘之后,我发现了一些类似的“问题”。 Tim Peters has said all there is to say:
除非有人自愿完成工作,否则C中没有任何实现是可继承的 使其成为可继承的;没有人自愿完成 [在此插入名称] 的工作 type subclassable。它肯定不在我的列表顶部 wink 。
另见this thread关于非子类可用类型的简短讨论。
实际上,所有替代解释器都会将行为复制到不同程度:Jython,Pyston,IronPython和PyPy(没有发现他们是如何做到的,但他们确实如此)。< / p>
答案 1 :(得分:5)
我很抱歉黑魔法
使用Forbiddenfruit和python的内置new
方法,我能够做到这一点:
from forbiddenfruit import curse
class MyThing(int):
def __new__(cls, *args, **kwargs):
magic_slice = slice(args[0], args[1])
curse(slice, 'otherstuff', args[2])
return magic_slice
thing = MyThing(1, 3, 'thing')
print 'hello world'[thing]
print thing.otherstuff
输出:
>>> el
>>> thing
我把它写成挑战只是因为每个人都说这是不可能的,我永远不会在生产代码中使用它有很多副作用,你应该再考虑一下你的结构和需求 的
答案 2 :(得分:-2)
切片无法进入return
类型,因为该方法不支持此功能。您可以详细了解__index__
special method here。
我只能想出一个直接调用你班级函数的解决方法:
class MyThing(object):
def __init__(self, start, stop, otherstuff):
self.start = start
self.stop = stop
self.otherstuff = otherstuff
def __index__(self):
return slice(self.start, self.stop)
thing = MyThing(1, 3, 'potato')
print 'Hello World'[thing.__index__()]
这将返回el
。