制作一个行为类似于切片的对象
Make an object that behaves like a slice
我们如何让 class 在适当的时候将自己表示为一个切片?
这没有用:
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
继承也不起作用。
切片不能在您的 return
类型中,因为该方法不支持它。您可以阅读有关 __index__
special method here 的更多信息。
我只能想出一个解决方法,直接调用 class:
中的函数
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__()]
这将 return el
。
TLDR:对于 list
和 tuple
.
等内置类型,无法自定义 classes 替换 slice
__index__
方法的存在纯粹是为了提供一个 索引 ,根据定义,它是 python 中的一个整数(参见 the Data Model)。您不能使用它来将对象解析为 slice
.
恐怕slice
好像是python专门处理的。该接口需要一个实际的切片;提供其签名(还包括 indices
方法)是不够的。正如您所发现的,您无法继承它,因此您无法创建新类型的 slice
。即使是 Cython 也不允许你继承它。
那么为什么 slice
很特别呢?很高兴你问。欢迎来到 CPython 的内部。看完后请洗手
因此 slice.rst
中描述了切片对象。注意这两个家伙:
.. c:var:: PyTypeObject PySlice_Type
The type object for slice objects. This is the same as :class:slice
in the
Python layer.
.. c:function:: int PySlice_Check(PyObject *ob)
Return true if ob is a slice object; ob must not be NULL.
现在,这实际上在 sliceobject.h
中实现为:
#define PySlice_Check(op) (Py_TYPE(op) == &PySlice_Type)
所以这里只允许 slice
类型。此检查实际上用于list_subscript
(和tuple subscript
,...)after 尝试使用索引协议(因此在__index__
切片是个坏主意)。自定义容器 class 可以自由覆盖 __getitem__
并使用其自己的规则,但这就是 list
(和 tuple
,...)的做法。
现在,为什么不能subclass slice
?好吧,type
实际上有一个标志表明某些东西是否可以被 subclassed。它被选中 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) 设置这个值的方式,但是有人得到这个错误的事实意味着它确实如此。这意味着你不能 subclass 它。
结束语:在记住了一些早已被遗忘的 C-(非)- 技能之后,我相当确定这不是严格意义上的优化。所有现有的检查和技巧仍然有效(至少我发现的那些)。
洗手并在互联网上四处搜索后,我发现了一些类似的 "issues"。 Tim Peters has said all there is to say:
Nothing implemented in C is subclassable unless somebody volunteers the work
to make it subclassable; nobody volunteered the work to make the [insert name here]
type subclassable. It sure wasn't at the top of my list wink.
另请参阅 this thread 以了解关于非子 class 类型的简短讨论。
几乎所有替代解释器都在不同程度上复制了行为:Jython, Pyston, IronPython 和 PyPy(没有找到他们是如何做到的,但他们做到了)。
I'M SORRY FOR THE DARK MAGIC
使用 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
我把它写成一个挑战只是因为每个人都说这是不可能的,我永远不会在生产代码中使用它它有很多副作用,你应该重新考虑你的结构和需求
我们如何让 class 在适当的时候将自己表示为一个切片?
这没有用:
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
继承也不起作用。
切片不能在您的 return
类型中,因为该方法不支持它。您可以阅读有关 __index__
special method here 的更多信息。
我只能想出一个解决方法,直接调用 class:
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__()]
这将 return el
。
TLDR:对于 list
和 tuple
.
slice
__index__
方法的存在纯粹是为了提供一个 索引 ,根据定义,它是 python 中的一个整数(参见 the Data Model)。您不能使用它来将对象解析为 slice
.
恐怕slice
好像是python专门处理的。该接口需要一个实际的切片;提供其签名(还包括 indices
方法)是不够的。正如您所发现的,您无法继承它,因此您无法创建新类型的 slice
。即使是 Cython 也不允许你继承它。
那么为什么 slice
很特别呢?很高兴你问。欢迎来到 CPython 的内部。看完后请洗手
因此 slice.rst
中描述了切片对象。注意这两个家伙:
.. c:var:: PyTypeObject PySlice_Type
The type object for slice objects. This is the same as :class:
slice
in the Python layer... c:function:: int PySlice_Check(PyObject *ob) Return true if ob is a slice object; ob must not be NULL.
现在,这实际上在 sliceobject.h
中实现为:
#define PySlice_Check(op) (Py_TYPE(op) == &PySlice_Type)
所以这里只允许 slice
类型。此检查实际上用于list_subscript
(和tuple subscript
,...)after 尝试使用索引协议(因此在__index__
切片是个坏主意)。自定义容器 class 可以自由覆盖 __getitem__
并使用其自己的规则,但这就是 list
(和 tuple
,...)的做法。
现在,为什么不能subclass slice
?好吧,type
实际上有一个标志表明某些东西是否可以被 subclassed。它被选中 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) 设置这个值的方式,但是有人得到这个错误的事实意味着它确实如此。这意味着你不能 subclass 它。
结束语:在记住了一些早已被遗忘的 C-(非)- 技能之后,我相当确定这不是严格意义上的优化。所有现有的检查和技巧仍然有效(至少我发现的那些)。
洗手并在互联网上四处搜索后,我发现了一些类似的 "issues"。 Tim Peters has said all there is to say:
Nothing implemented in C is subclassable unless somebody volunteers the work to make it subclassable; nobody volunteered the work to make the [insert name here] type subclassable. It sure wasn't at the top of my list wink.
另请参阅 this thread 以了解关于非子 class 类型的简短讨论。
几乎所有替代解释器都在不同程度上复制了行为:Jython, Pyston, IronPython 和 PyPy(没有找到他们是如何做到的,但他们做到了)。
I'M SORRY FOR THE DARK MAGIC
使用 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
我把它写成一个挑战只是因为每个人都说这是不可能的,我永远不会在生产代码中使用它它有很多副作用,你应该重新考虑你的结构和需求