Deekor
Deekor

Reputation: 9499

2 inputs to a function?

So Ive been giving the following code in a kind of sort of python class. Its really a discrete math class but he uses python to demonstrate everything. This code is supposed to demonstate a multiplexer and building a xor gate with it.

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)

In the xor2 function I dont understand the syntax behind return mux41(0,1,1,0)(a,b) the 1's and 0's are the input to the mux function, but what is the (a,b) doing?

Upvotes: 5

Views: 576

Answers (2)

steveha
steveha

Reputation: 76715

That is fairly advanced code to throw at Python beginners, so don't feel bad it wasn't obvious to you. I also think it is rather trickier than it needs to be.

def mux41(i0,i1,i2,i3):
    return lambda s1,s0:{(0,0):i0,(0,1):i1,(1,0):i2,(1,1):i3}[(s1,s0)]

This defines a function object that returns a value based on two inputs. The two inputs are s1 and s0. The function object builds a dictionary that is pre-populated with the four values passed int to mux41(), and it uses s0 and s1 to select one of those four values.

Dictionaries use keys to look up values. In this case, the keys are Python tuples: (0, 0), (0, 1), (1, 0), and (1,1). The expression (s1,s0) is building a tuple from the arguments s0 and s1. This tuple is used as the key to lookup a value from the dictionary.

def xor2(a,b):
    return mux41(0,1,1,0)(a,b)

So, mux41() returns a function object that does the stuff I just discussed. xor2() calls mux41() and gets a function object; then it immediately calls that returned function object, passing in a and b as arguments. Finally it returns the answer.

The function object created by mux41() is not saved anywhere. So, every single time you call xor2(), you are creating a function object, which is then garbage collected. When the function object runs, it builds a dictionary object, and this too is garbage collected after each single use. This is possibly the most complicated XOR function I have ever seen.

Here is a rewrite that might make this a bit clearer. Instead of using lambda to create an un-named function object, I'll just use def to create a named function.

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)

EDIT: Here is what I would have written if I wanted to make a table-lookup XOR in Python.

_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]

We build the lookup dictionary once, then use it directly from xor2(). It's not really necessary to make an explicit temp variable in xor2() but it might be a bit clearer. You could just do this:

def xor2(a,b):
    return _d_xor2[(a, b)]

Which do you prefer?

And of course, since Python has an XOR operator built-in, you could write it like this:

def xor2(a,b):
    return a ^ b

If I were writing this for real I would probably add error handling and/or make it operate on bool values.

def xor2(a,b):
    return bool(a) ^ bool(b)

EDIT: One more thing just occurred to me. In Python, the rule is "the comma makes the tuple". The parentheses around a tuple are sometimes optional. I just checked, and it works just fine to leave off the parentheses in a dictionary lookup. So you can do this:

def xor2(a,b):
    return _d_xor2[a, b]

And it works fine. This is perhaps a bit too tricky? If I saw this in someone else's code, it would surprise me.

Upvotes: 5

Volatility
Volatility

Reputation: 32300

The (a, b) is actually the input to the lambda function that you return in the mux41 function.

Your mux41 function returns a lambda function which looks like it returns a value in a dictionary based on the input to the mux41 function. You need the second input to say which value you want to return.

It is directly equivalent to:

def xor2(a,b):
    f = mux41(0,1,1,0)
    return f(a,b)

Upvotes: 12

Related Questions