我很难理解python 3.10.0中这些lambda函数的行为
我试图从lambda演算中定义NOT
逻辑运算符(参见wikipedia上的定义)下面的实现是正确的:
In [1]: TRUE = lambda a: lambda b: a
...: FALSE = lambda a: lambda b: b
...: NOT = lambda a: a(FALSE)(TRUE)
...: assert NOT(FALSE) == TRUE
但是,当我尝试对FALSE
或TRUE
进行文字替换时,代码失败
In [2]: NOT1 = lambda a: a(FALSE)(lambda a: lambda b: a)
...: assert NOT1(FALSE) == TRUE
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
Cell In[2], line 2
1 NOT1 = lambda a: a(FALSE)(lambda a: lambda b: a)
----> 2 assert NOT1(FALSE) == TRUE
AssertionError:
谁能告诉我为什么会这样?Python函数==
通过对象标识工作。(尝试以任何其他方式实现它的范围从"痛苦的不一致";到"完全不可能"。)您创建了另一个与NOT
函数具有相同行为的函数,但它不是同一个函数对象,因此==
表示它们不相等。
主要原则是每次调用lambda
都会创建一个新函数.
你的第一个单元格是:
def TRUE(a):
def _inner(b):
return a
return _inner
def FALSE(a):
def _inner(b):
return b
return _inner
def NOT(a):
return a(FALSE)(TRUE)
执行NOT(FALSE)
导致FALSE(FALSE)(TRUE)
导致FALSE._inner(TRUE)
返回TRUE,一个函数.
现在你的第二个单元格,执行NOT1(FALSE)
结果FALSE(FALSE)(lambda...)
结果FALSE._inner(lambda...)
返回lambda...
,另一个函数,但不是在TRUE
中定义的函数. 还记得我之前说的原则吗?lambda
语句创建新函数.
比较两个函数时,==
运算符与函数的内容无关。它只关心被比较的项是否指向内存中的完全相同的函数。但是,由于TRUE
和lambda...
是两个独立的函数,即使内容相同,它们也位于不同的内存位置,因此==
的比较失败。
感谢所有澄清==
操作符问题的人。
我试图理解这两个函数的不同之处。让我们从更简单的例子
开始In [18]: id(f)
Out[18]: 140465987909328
In [19]: id(g)
Out[19]: 140465990159088
In [20]: assert f==g
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
Cell In[20], line 1
----> 1 assert f==g
AssertionError:
显然这两个对象有不同的id
s
In [21]: id(f)
Out[21]: 140465987909328
In [22]: id(g)
Out[22]: 140465990159088
对我来说不太明显的是它们确实有不同的哈希值
In [23]: f.__hash__()
Out[23]: 8779124244333
In [24]: g.__hash__()
Out[24]: 8779124384943
我需要的等价性测试可以在__code__.co_code
函数属性上进行。
In [25]: f.__code__.co_code
Out[25]: b'|x00Sx00'
In [26]: g.__code__.co_code
Out[26]: b'|x00Sx00'
In [27]: assert f.__code__.co_code == g.__code__.co_code
然而,我很好奇这两个函数对象究竟在哪里不同。查看__code__
的方法和属性,我们有
In [28]: dir(f.__code__)
Out[28]:
['__class__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'co_argcount',
'co_cellvars',
'co_code',
'co_consts',
'co_filename',
'co_firstlineno',
'co_flags',
'co_freevars',
'co_kwonlyargcount',
'co_lines',
'co_linetable',
'co_lnotab',
'co_name',
'co_names',
'co_nlocals',
'co_posonlyargcount',
'co_stacksize',
'co_varnames',
'replace']
我们试着验证
In [29]: L = [x for x in dir(f.__code__) if x.startswith('co_')]
In [29]: for x in L:
...: print(f"{x:20s}", getattr(f.__code__,x)==getattr(g.__code__,x))
...:
co_argcount True
co_cellvars True
co_code True
co_consts True
co_filename False
co_firstlineno True
co_flags True
co_freevars True
co_kwonlyargcount True
co_lines False
co_linetable True
co_lnotab True
co_name True
co_names True
co_nlocals True
co_posonlyargcount True
co_stacksize True
co_varnames True
唯一不同的字段是co_filename
和co_lines()
:
In [30]: f.__code__.co_filename, g.__code__.co_filename
Out[30]: ('<ipython-input-1-242f7af8e2bb>', '<ipython-input-2-a597939a9a2e>')
In [31]: f.__code__.co_lines()
Out[31]: <line_iterator at 0x7f10948790c0>
In [32]: g.__code__.co_lines()
Out[32]: <line_iterator at 0x7f10945178c0>
In [33]: list(f.__code__.co_lines())
Out[33]: [(0, 4, 1)]
In [34]: list(g.__code__.co_lines())
Out[34]: [(0, 4, 1)]
不能修改co_filename
字段:
In [35]: f.__code__.co_filename = 'something_else'
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[35], line 1
----> 1 f.__code__.co_filename = 'something_else'
AttributeError: readonly attribute
在我看来,唯一不同的是这两个字段。
有趣的是,有一种情况下,两个变量名不同的lambda函数也应该被认为是相同的:
In [40]: f = lambda x:x
In [41]: g = lambda y:y
In [42]: f.__code__.co_code
Out[42]: b'|x00Sx00'
In [43]: g.__code__.co_code
Out[43]: b'|x00Sx00'
事实上,就co_code
而言,它们是。
总之,我认为为函数引入equivalence
操作符可能是有争议的,不同于__eq__
操作符,可能是语法~=
的东西,这似乎还没有被采用。你的想法呢?