python del函数如何在不调用__getitem__的情况下工作

时间:2019-03-21 17:25:26

标签: python magic-methods python-collections

在python中,当对象的类定义一个对象时,该对象是可下标的

__getitem__(self, k)

方法,允许我们通过方括号语法“获取项目”:

obj[k]

内置del函数的语法为:

del(obj[k])

这将从(可订阅的)对象obj中删除项目k。但显然,无需调用特殊的getitem方法。

请参见下面的示例

>>> class A:
...     def __init__(self, d):
...         self._d = d
...
...     def __getitem__(self, k):
...         print("Calling __getitem__")
...         return self._d[k]
...
...     def __delitem__(self, k):
...         del(self._d[k])
...
>>>
>>> a = A({1: 'one', 2: 'two', 3: 'three'})
>>> a._d
{1: 'one', 2: 'two', 3: 'three'}
>>> a[2]
Calling __getitem__
'two'
>>> del(a[2])
>>> # Note there was no "Calling __getitem__" print!

因此,似乎在a [2]将工作转发到getitem方法之前,解释器意识到了del上下文,并绕过了它,直接调用

a.__delitem__(2)

相反。

这是怎么工作的?

最重要的是:这种机制可定制吗?

例如,我可以编写一个函数foo这样

foo(obj[k])

从不打电话

obj.__getitem__(k)

,例如

obj.foo(k)

2 个答案:

答案 0 :(得分:2)

del 不是一个功能。因为它不是函数,所以可以这样做。这是为什么这不是一个函数。这是del语句中语言内置的关键字。

要记住,delreturn之类的东西不是函数(并避免意外的优先顺序意外),最好不要在“参数”周围加上括号:

del whatever

而不是

del(whatever)

del不带对象并将其删除。 del右边的东西不是要求值的表达式。这是一种target_list,与在赋值语句中=左侧出现的语法相同:

target_list     ::=  target ("," target)* [","]
target          ::=  identifier
                     | "(" [target_list] ")"
                     | "[" [target_list] "]"
                     | attributeref
                     | subscription
                     | slicing
                     | "*" target

要删除像obj[k]这样的 subscription 目标,Python计算表达式obj和表达式k来产生两个对象,然后调用{{1 }}方法,将第一个对象与第二个对象作为参数。 __delitem__永远不会被评估为表达式,尽管其中的一部分会被评估。


所有这些都依赖于编译器和语法支持,并且不能对任意用户定义的函数执行。

答案 1 :(得分:1)

您正在编写示例代码,好像layoutSubviews是一个函数 参数,并假设必须首先通过以下方式处理参数del a[2]。但严格来说,__getitem__()statement。这意味着语言解析器可以对它进行特殊处理 方式–换句话说,不一定像函数调用一样。

我们可以使用dis软件包来获得一些提示。请注意del 操作直接表示为非常具体的del操作。 它绕过了DELETE_SUBSCR示例所使用的BINARY_SUBSCR步骤。

len

输出(摘要):

from dis import dis

def f(xs):
    del xs[2]

def g(xs):
    len(xs[2])

print('\n# del')
dis(f)
print('\n# len')
dis(g)