dispatch method table - Python 中的函数为什么不能加括号?

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

我想了解函数 tables 中调度 table 的设计。

这是我最初编码的内容

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())

但是,此函数将调用 2 函数 self.test()self.test2(),而不仅仅是与键 self.test() 关联的函数。

另一方面,对不带括号的调度 table 进行编码将执行指定的映射函数

像这样

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

我参考了不同的资源试图理解,但它们没有解释行为上的差异。

我想知道是否有人可以提供一些关于这个问题的启示。

参考:

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

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

为了理解这个问题,让我们像解释器一样逐行阅读代码:

# 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.

因此,您在

行中有 2 次调用 self.test()
mapping = {1:self.test(), 2:self.test2()}
# AND
print(type(self.test()))

并在第

行调用 self.test2() 一次
mapping = {1:self.test(), 2:self.test2()}

如果您希望能够调用存储在 mapping 中的内容,您需要在创建 mapping 时删除这些括号。这样您就可以将函数对象存储在字典中而不是函数结果中。

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

这是完全不同的。带括号 - 函数调用的结果,不带 - 函数对象。