在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)
答案 0 :(得分:2)
del
不是一个功能。因为它不是函数,所以可以这样做。这是为什么这不是一个函数。这是del
语句中语言内置的关键字。
要记住,del
和return
之类的东西不是函数(并避免意外的优先顺序意外),最好不要在“参数”周围加上括号:
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)