为什么当我使用 [:] 时,我的子类的 __getitem__ 和 __setitem__ 没有被调用?
Why are my subclass's __getitem__ and __setitem__ not called when I use [:]?
我正在开发 Python 2.7,我正在尝试从继承 list
的 class 重载 __getitem__
和 __setitem__
。
假设我有这个 class A
:
class A(list):
def __getitem__(self, key):
print "GET!"
def __setitem__(self, key, value):
print "SET!"
加上方括号,应该调用A.__getitem__
或A.__setitem__
。通常是这样,但是当我使用 [:]
时,会调用父实现。为什么?为什么 [::]
有效?
a = A([1])
a[1] # prints GET!
a["1"] # prints GET!
a[::] # prints GET!
a[slice(None)] # prints GET!
a[:] # returns the list [1]
与__setitem__
相同:
a[1] = 2 # prints SET!
a[::] = 2 # prints SET!
a[slice(None)] = 2 # prints SET!
a[:] = [2] # changes the list
那是因为在 Python 2 [1] [:]
以及具有 start[=61= 的一维切片中] and/or end(但不是在指定 step 时)像 [1:]
、[:3]
或 [1:3]
如果实施,则通过 __getslice__
and __setslice__
。如果未实施,它们也会转到 __getitem__
和 __setitem__
)。引用文档:
Notice that these methods [__*slice__
] are only invoked when a single slice with a single colon is used, and the slice method is available. For slice operations involving extended slice notation, or in absence of the slice methods, __getitem__()
, __setitem__()
or __delitem__()
is called with a slice object as argument.
在你的情况下,你从list
继承它们(list
实现它们)所以它绕过了你的__getitem__
和__setitem__
在简单的切片情况下。
例如,您可以重写 __*slice__
方法来验证 [:]
调用是否真的到达那里:
class A(list):
def __getitem__(self, key):
print "GET!"
def __setitem__(self, key, value):
print "SET!"
def __getslice__(self, i, j):
print "GETSLICE!"
def __setslice__(self, i, j, seq):
print "SETSLICE!"
然而,这些仅在仅传入一个切片且仅在传递的切片没有步骤时调用。所以 [::]
不会去那里,因为它有一个步骤(即使它是隐含的)。但是 [:,:]
也不会进入这些,因为它被翻译成 tuple(slice(None), slice(None))
这不是一个简单的切片而是切片的元组。如果你自己传入一个 slice
实例,它也不会进入这些 __*slice__
方法,这就是为什么 [slice(None)]
即使看似等同于 [:]
直接进入 __*item__
而不是 __*slice__
.
[1] 在 Python 3 中删除了 __*slice__
方法,因此 [whatever]
索引将转到 __*item__
方法。
我正在开发 Python 2.7,我正在尝试从继承 list
的 class 重载 __getitem__
和 __setitem__
。
假设我有这个 class A
:
class A(list):
def __getitem__(self, key):
print "GET!"
def __setitem__(self, key, value):
print "SET!"
加上方括号,应该调用A.__getitem__
或A.__setitem__
。通常是这样,但是当我使用 [:]
时,会调用父实现。为什么?为什么 [::]
有效?
a = A([1])
a[1] # prints GET!
a["1"] # prints GET!
a[::] # prints GET!
a[slice(None)] # prints GET!
a[:] # returns the list [1]
与__setitem__
相同:
a[1] = 2 # prints SET!
a[::] = 2 # prints SET!
a[slice(None)] = 2 # prints SET!
a[:] = [2] # changes the list
那是因为在 Python 2 [1] [:]
以及具有 start[=61= 的一维切片中] and/or end(但不是在指定 step 时)像 [1:]
、[:3]
或 [1:3]
如果实施,则通过 __getslice__
and __setslice__
。如果未实施,它们也会转到 __getitem__
和 __setitem__
)。引用文档:
Notice that these methods [
__*slice__
] are only invoked when a single slice with a single colon is used, and the slice method is available. For slice operations involving extended slice notation, or in absence of the slice methods,__getitem__()
,__setitem__()
or__delitem__()
is called with a slice object as argument.
在你的情况下,你从list
继承它们(list
实现它们)所以它绕过了你的__getitem__
和__setitem__
在简单的切片情况下。
例如,您可以重写 __*slice__
方法来验证 [:]
调用是否真的到达那里:
class A(list):
def __getitem__(self, key):
print "GET!"
def __setitem__(self, key, value):
print "SET!"
def __getslice__(self, i, j):
print "GETSLICE!"
def __setslice__(self, i, j, seq):
print "SETSLICE!"
然而,这些仅在仅传入一个切片且仅在传递的切片没有步骤时调用。所以 [::]
不会去那里,因为它有一个步骤(即使它是隐含的)。但是 [:,:]
也不会进入这些,因为它被翻译成 tuple(slice(None), slice(None))
这不是一个简单的切片而是切片的元组。如果你自己传入一个 slice
实例,它也不会进入这些 __*slice__
方法,这就是为什么 [slice(None)]
即使看似等同于 [:]
直接进入 __*item__
而不是 __*slice__
.
[1] 在 Python 3 中删除了 __*slice__
方法,因此 [whatever]
索引将转到 __*item__
方法。