Python-lambdas,不是weakrefs,不是指针,不确定是什么

Python-lambdas,不是weakrefs,不是指针,不确定是什么,python,lambda,Python,Lambda,我有一个业余爱好者pubsub库,它使用了大量的weakref,但我最近注意到lambdas在执行过程中似乎非常相似,除了一些让我印象深刻的差异外。。。违反直觉。(如果只是因为我不确定兰巴斯到底在做什么) 以下面的类作为可能要发布sub的对象的示例: >>> class A(object): ... def __init__(self, x): ... self.x = x ... def foo(self): ...

我有一个业余爱好者pubsub库,它使用了大量的
weakref
,但我最近注意到lambdas在执行过程中似乎非常相似,除了一些让我印象深刻的差异外。。。违反直觉。(如果只是因为我不确定兰巴斯到底在做什么)

以下面的类作为可能要发布sub的对象的示例:

>>> class A(object):
...     def __init__(self, x):
...             self.x = x
...     def foo(self):
...             self.x += 1
...     def bar(self):
...             return "my x is %d" % self.x
... 
>>> Stick = A(15)
>>> Stick.x
15
>>> Stick.foo()
>>> Stick.bar()
'my x is 16'
无需导入
weakref
库并对绑定方法的自定义弱引用进行黑客攻击,就可以使用
lambda
执行类似操作

this = lambda: Stick.foo
that = lambda: Stick.bar
在创建此和的前后使用
sys.getrefcount
将显示主对象或其绑定方法的引用计数没有更改

>>> sys.getrefcount(Stick)
2
>>> sys.getrefcount(Stick.foo)
1
>>> sys.getrefcount(Stick.bar)
1
events = [this, that]
此外,“not weakrefs”也可以放在容器中,而不改变对象或其绑定方法的refcount

>>> sys.getrefcount(Stick)
2
>>> sys.getrefcount(Stick.foo)
1
>>> sys.getrefcount(Stick.bar)
1
events = [this, that]
最后,可以用双括号调用“not weakref”lambda。看起来有点难看,但也有一些“弱边界方法”的黑客(包括我自己的),所以这是可以接受的

>>> for e in events:
...     e()()
... 
'my x is 17'
>>> 
看起来没问题——直到删除主对象

>>> del Stick
>>> for e in events:
...     e()()
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 1, in <lambda>
NameError: global name 'Stick' is not defined
>>> 
请注意,新对象也没有调用其
foo
bar
方法-因此这实际上是“指向”对象的同一命名实例

>>> Dave = A(15) #sets Dave.x to 15
>>> for e in events:
...     e()()
... 
'my x is 779'
>>> Dave.x
15
>>> Dave.bar()
'my x is 15'
>>> 
这是我第一次看到一个对象在被删除后可以如此轻松地“重新调用”,或者甚至成功地引用了一个不需要的变量。它“感觉”非常神奇

Python文档只是将lambdas比作匿名函数,并没有真正讨论底层(我可以说)——那么在定义和使用lambdas时到底发生了什么呢


附带问题;那么,这种发布方式公平吗?或者说,我们之所以倾向于看到这种方式,是因为它的便利性和显而易见的普遍性?(与之相反,比如说,
try/except
ing通过lambda,不再返回有效的函数或绑定方法)

您正在计算错误的引用。通过创建lambda,此lambda将继承从中创建的堆栈框架,其中包含其所有局部变量(在本例中为全局变量)。因此,您正在创建对堆栈帧的更多引用,其中只包含对实际对象的一个引用。

this=lambda:Stick.foo
与写入
def this():return Stick.foo
相同。不需要魔法。在调用lambda并指定结果之前,不会将引用创建为Stick.foo…啊,天哪,是的-如果我执行类似于
def eggs(func)的操作:返回lambda:func
,然后传递一个绑定方法,则对象的refcount值为+1。纳特群岛