Home > database >  Why can't we add brackets for functions in dispatch method table - Python?
Why can't we add brackets for functions in dispatch method table - Python?

Time:10-19

I am trying to understand the design of dispatch table in function tables.

Here is what I initially coded

class Aave():
    def __init__(self,address):
        self.address = address
    def function_map(self):
        mapping = {1:self.test(),2:self.test2()}
        print(type(self.test()))
        return mapping[self.address]()
    
    def test(self):
        print(1)
        return 1
    
    def test2(self):
        print(2)
        return 2
a = Aave(1)
print(a.function_map())

However, this function would call the 2 function self.test() and self.test2() instead of just the function associated with key self.test().

On the other hand, coding the dispatch table without brackets would perform the specified mapped function

like as such

    def function_map(self):
        mapping = {1:self.test,2:self.test2}
        print(type(self.test()))
        return mapping[self.address]()

I have referred to different resources trying to understand, but they don't explain the difference in behaviour.

I was wondering if anyone could provide some enlightenment regarding this issue.

Referred to:

https://www.oreilly.com/library/view/python-cookbook/0596001673/ch01s07.html

https://betterprogramming.pub/dispatch-tables-in-python-d37bcc443b0b

CodePudding user response:

To understand the issue, let's read the code as the interpreter does, line by line:

# First of all object creation is executed
a = Aave(1)

# This invokes method __init__ of class Aave, hence next step is 
a.address = 1

# After the creation of a class instance, interpreter tries to run
print(a.function_map())

# But since value of a.function_map() is unknown it needs to be calculated first
# Hence, interpreter enters function_map method of class Aave
# Execution of
mapping = {1:self.test(), 2:self.test2()}
# requires the test() and test2() to be evaluated. Since brackets indicate function call

# Thus, test() runs, prints 1 and returns 1. If we could see the value of 
# mapping after this, it would have been:
# {1: 1, 2: <unknown yet result of self.test2()>}
#     ^
# This value is the result of self.test()

# Next self.test2() is evaluated, since it also has brackets and needs to be called
# test2() runs, prints 2 and returns 2.
# After this step, mapping looks like {1: 1, 2: 2}
#                                         ^     ^
#                          Had this already     result of self.test2()

# After this mapping is completely known and next line may be evaluated.
# Evaluating 
print(type(self.test()))
# causes one more call to self.test, 
# since it also has brackets.

# And when you finally evaluate last line
return mapping[self.address]()
# Keeping in mind, that mapping was {1: 1, 2: 2}, you try to take value by key 1 from mapping,
# which is 1 (int). And call it (since you put "()"). It causes error, because 1 int is not callable.

As a result, you have 2 calls to self.test() in lines

mapping = {1:self.test(), 2:self.test2()}
# AND
print(type(self.test()))

and one call to self.test2() in line

mapping = {1:self.test(), 2:self.test2()}

If you wanted to be able to call what you store in mapping, you would need to remove those brackets in mapping creation. This way you would store function-objects in a dict instead of function results.

mapping = {1:self.test(), 2:self.test2()}  # Call functions and store results
# VS
mapping = {1:self.test, 2:self.test2}  # Store functions themselves

It's the whole difference. With brackets - result of function call, without - function-object.

  • Related