作出这样的行为就像一个切片对象

问题描述 投票:6回答:3

我们怎样才能使一个类代表本身作为一个切片在适当的时候?

这并没有工作:

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继承也不起作用。

python slice
3个回答
7
投票

TLDR:这是不可能让自定义类取代slice为内建类型如listtuple


该方法__index__纯粹的存在是为了提供一种索引,其是由定义在python的整数(参见the Data Model)。你不能用它解决的对象到slice

恐怕slice似乎是由蟒蛇特殊处理。该接口要求的实际切片;提供它的签名(其也包括indices方法)是不够的。正如你已经发现了,你不能继承它,所以你不能创建新类型slices的。即使是用Cython不会让你从它继承。


那么,为什么是slice特别?很高兴你问。欢迎到CPython中的内脏。请阅读本后洗手。

所以切片对象在slice.rst描述。请注意这两个家伙:

.. C:VAR :: PyTypeObject PySlice_Type

对于切片对象的类型的对象。这是相同的:类:在Python层slice

.. C:如果作业是切片对象函数:: INT PySlice_Check(的PyObject * 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(UN)如何设置这个值,而是一个得到这个错误的事实意味着它。这意味着你不能继承它。


结束语:记住一些长期被遗忘的C-(非)-skills后,我相当肯定这是不是严格意义上的优化。所有现有的检查和技巧,仍能正常工作(至少是我发现)。

洗我的手,在互联网上搜集了之后,我发现类似的“问题”的几个引用。 Tim Peters has said all there is to say:

用C语言实现没有什么是子类化,除非有人志愿者,使其子类化工作;没有人自告奋勇的工作,使[插入的名字在这里]类型子类化。这肯定不是我的名单眨眼的顶部。

另见this thread关于非subclass'able类型的一个简短的讨论。

几乎所有的替代口译复制行为在不同程度:JythonPystonIronPython和PyPy(没搞清楚他们是如何做到这一点,但是他们这样做)。


5
投票

I'M SORRY FOR THE DARK MAGIC

使用qazxsw POI和建造qazxsw POI方法我能做到这一点,Python的:

Forbiddenfruit

输出:

new

我写的是一个挑战,只是因为大家都说这是不可能的,我永远不会使用它的生产代码它有许多副作用,你应该重新考虑你的结构和需求


-2
投票

切片不能在你的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 return。我只能拿出直接调用你的类功能的解决方法:

__index__

这将返回special method here

© www.soinside.com 2019 - 2024. All rights reserved.