函数可以接受两个输入吗?
我在上一个类似于Python的课程中学到了以下代码。其实这是一门离散数学课,但老师用Python来演示所有内容。这段代码是用来展示一个多路复用器(multiplexer)以及如何用它构建一个异或门(xor gate)。
def mux41(i0,i1,i2,i3):
return lambda s1,s0:{(0,0):i0,(0,1):i1,(1,0):i2,(1,1):i3}[(s1,s0)]
def xor2(a,b):
return mux41(0,1,1,0)(a,b)
在xor2
这个函数里,我不太明白return mux41(0,1,1,0)(a,b)
这段代码的语法。这里的1和0是传给多路复用器的输入,但后面的(a,b)又是干嘛的呢?
2 个回答
这段代码对刚学Python的人来说有点复杂,所以你不用觉得自己不明白有什么问题。我觉得它比实际需要的要复杂一些。
def mux41(i0,i1,i2,i3):
return lambda s1,s0:{(0,0):i0,(0,1):i1,(1,0):i2,(1,1):i3}[(s1,s0)]
这段代码定义了一个函数,它根据两个输入返回一个值。这两个输入是 s1
和 s0
。这个函数会创建一个字典,里面预先填充了传给 mux41()
的四个值,然后用 s0
和 s1
来选择这四个值中的一个。
字典是通过键来查找值的。在这里,键是Python的元组:(0, 0)
、(0, 1)
、(1, 0)
和 (1, 1)
。表达式 (s1, s0)
是从参数 s0
和 s1
创建一个元组。这个元组用作查找字典中值的键。
def xor2(a,b):
return mux41(0,1,1,0)(a,b)
所以,mux41()
返回一个函数对象,完成我刚才说的事情。xor2()
调用 mux41()
并得到一个函数对象;然后它立即调用这个返回的函数对象,传入 a
和 b
作为参数。最后,它返回结果。
由 mux41()
创建的函数对象并没有被保存。所以,每次你调用 xor2()
时,都会创建一个新的函数对象,然后这个对象会被垃圾回收。这个函数对象运行时,会构建一个字典对象,这个字典在每次使用后也会被垃圾回收。这可能是我见过的最复杂的XOR函数。
这里有一个重写的版本,可能会让这个过程更清晰。与其使用 lambda
创建一个没有名字的函数对象,不如用 def
创建一个有名字的函数。
def mux41(i0,i1,i2,i3):
def mux_fn(s1, s0):
d = {
(0,0):i0,
(0,1):i1,
(1,0):i2,
(1,1):i3
}
tup = (s1, s0)
return d[tup]
return mux_fn
def xor2(a,b):
mux_fn = mux41(0,1,1,0)
return mux_fn(a,b)
编辑:如果我想在Python中做一个查表的XOR,我会这样写。
_d_xor2 = {
(0,0) : 0,
(0,1) : 1,
(1,0) : 1,
(1,1) : 0
}
def xor2(a,b):
tup = (a, b)
return _d_xor2[tup]
我们只需构建一次查找字典,然后直接在 xor2()
中使用它。其实在 xor2()
中不一定需要明确的临时变量,但这样可能会更清晰。你也可以直接这样做:
def xor2(a,b):
return _d_xor2[(a, b)]
你更喜欢哪种方式?
当然,由于Python内置了XOR运算符,你也可以这样写:
def xor2(a,b):
return a ^ b
如果我真的在写这个,我可能会添加错误处理,或者让它处理 bool
值。
def xor2(a,b):
return bool(a) ^ bool(b)
编辑:我刚想到一件事。在Python中,有个规则是“逗号构成元组”。元组的括号有时是可选的。我刚检查了一下,省略括号在字典查找中也能正常工作。所以你可以这样做:
def xor2(a,b):
return _d_xor2[a, b]
这样也可以正常工作。这可能有点太复杂了?如果我在别人的代码中看到这个,我会感到惊讶。
这里的 (a, b)
实际上是你在 mux41
函数中返回的 lambda
函数的输入。
你的 mux41
函数返回了一个 lambda
函数,这个函数看起来是根据传给 mux41
函数的输入,从一个字典中返回一个值。你需要第二个输入来指定你想要返回哪个值。
这实际上是等价于:
def xor2(a,b):
f = mux41(0,1,1,0)
return f(a,b)