简体   繁体   English

请帮助我理解这段代码是如何工作的(我认为正确的术语是“柯里化”……?)

[英]Please help me understand how this piece of code works (I think the correct term is 'currying'...?)

I am having a hard time understanding how this code works:我很难理解这段代码是如何工作的:

class add(int):
    
    def __call__(self, int):
        return add(self + int)

result = add(2)
print(result(4))

The int 2 seems to get stored inside result(not sure if that is the case tbh), such that when we print(result), the output is 2. When print(result(4)) is ran, the output becomes 6. My question is...why is this? int 2 似乎存储在结果中(不确定是否是这种情况 tbh),这样当我们打印(结果)时,output 为 2。当运行打印(结果(4))时,output 变为 6。我的问题是……这是为什么? Is the number 2, in fact, being stored inside result?实际上,数字 2 存储在结果中吗? If we instantiate the add class without an argument, the result variable will output the number 0. What is happening here under the hood??如果我们在没有参数的情况下实例化 add class,结果变量将为 output 数字 0。这里发生了什么?

I want to understand why calling result(2)(3)(4) outputs 9.我想了解为什么调用 result(2)(3)(4) 输出 9。

What this class does, it gives integers an ability to be called as a function, so that a(b) actually means a+b .这个 class 的作用是,它使整数能够被称为 function,因此a(b)实际上意味着a+b Imagine one day this feature is added to the python interpreter.想象有一天,这个功能被添加到 python 解释器中。 Then you could write 2(3) and get 5 .然后你可以写2(3)并得到5 But that 5 is still callable, so we can do 5(4) and get 9 , or, chained together, 2(3)(4) => 9 .但是5仍然是可调用的,所以我们可以执行5(4)并得到9 ,或者,链接在一起, 2(3)(4) => 9

In actual python this is not possible (number literals are always int ), so we have to explicitly name our class (as in add(2)(3)(4) ), but the principle remains the same.在实际的 python 中这是不可能的(数字文字总是int ),所以我们必须明确命名我们的 class (如add(2)(3)(4) ),但原则保持不变。

"Currying" is not what's happening here. “柯里化”不是这里发生的事情。

add is a class that subclasses int . add是 class 的子类int As such, it behaves exactly as we would expect int instances to behave.因此,它的行为与我们期望的int实例的行为完全一样。 So, for example, its "default"y value is 0. That is why print(add()) is 0 (since int() is 0).因此,例如,它的“默认”y 值为 0。这就是print(add())为 0 的原因(因为int()为 0)。

Now, we implemented the __add__ method.现在,我们实现了__add__方法。 According to the data-model , the __add__ method allows instances of classes that implement it to be callable, ie be used to the left of () , with or without argument.根据data-model__add__方法允许实现它的类的实例是可调用的,即用于()的左侧,有或没有参数。

Since you allowed __call__ to accept an argument and you add this argument to the value that the instance currently represents (remember that add instances behave just like a normal int would), we can call instances of add with an argument and expect the behavior you observed.由于您允许__call__接受参数并将此参数添加到实例当前表示的值(请记住add实例的行为就像普通的int一样),我们可以使用参数调用add的实例并期望您观察到的行为.

To recap, add(2) gives us an object that represents the integer 2 (just like int(2) would) with the added functionality of being able to call it with an argument that will be added to its own value (so add(2)(3) is just 2 + 3 ).回顾一下, add(2)为我们提供了一个 object 表示 integer 2 (就像int(2)一样),并增加了能够使用将添加到它自己的值的参数来调用它的功能(所以add(2)(3)就是2 + 3 )。

We can add some print s to see what is going on, and it is better to not use the name int in the definition of __call__ since we don't want to shadow the type int (that the add class subclasses).我们可以添加一些print以查看发生了什么,最好不要在__call__的定义中使用名称int ,因为我们不想隐藏类型int (即add class 子类)。 Ignore the call to super().__init__() if you are not familiar with it already, it is there to allow us to print the message).如果您还不熟悉它,请忽略对super().__init__()的调用,它允许我们打印消息)。

class add(int):
    def __init__(self, own_value):
        print(f"Created 'add' with own_value {own_value}")
        super().__init__()

    def __call__(self, number):
        print(f"Inside __call__ with number {number}, will return new 'add' with own_value {self + number}")
        return add(self + number)


result = add(2)
print(result(4))

outputs产出

Created 'add' with own_value 2
Inside __call__ with number 4, will return new 'add' with own_value 6
Created 'add' with own_value 6
6

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM