在 class 中的默认参数中使用 functools.partial 时的意外行为

Surprising behaviour when using functools.partial in default argument inside a class

class A:

    def _add(a, b):
        return a + b
    
    def f_add():
        return _add
    
    def lambda_add():
        return lambda x, y: _add(x, y)
    
    def lambda_arg_add(l=lambda x, y: _add(x, y)):
        return l

    def partial_add():
        return partial(_add)
    
    def partail_arg_add(f=partial(_add)):
        return f


A.f_add()(1, 2)

A.lambda_add()(1, 2)

A.lambda_arg_add()(1, 2)

A.partial_add()(1, 2)

A.partail_arg_add()(1, 2)

除最后一个函数调用外,所有函数调用都会引发错误,指出 _add 未定义,但对 partail_arg_add 的调用执行成功。这背后的逻辑是什么?为什么解释器在创建部分函数时知道在哪里寻找 _add 但只有当它作为默认参数完成时才知道?

functools.partial 不涉及此行为。

这是因为默认 arg 是在函数定义处创建的,在 class 定义期间,它出现在 class 的范围内,因此您不需要任何“self. ".

这就是它起作用的原因:

class Example:
    def A(self):
        pass

    def B(self, x=print(A, 1)):
        print(self.A, 2)

    print(A, 3)

输出:

<function Example.A at 0x7fcf8ebc5950> 1
<function Example.A at 0x7fcf8ebc5950> 3

即使不调用任何 Example.B(),它也应该在定义 class 时打印 <function Example.A at 0x7fcf8ebc5950> 1 和 3。

但是您不能使用尚未创建的方法创建部分 class

或者,也许你可以,但我不知道有什么方法可以做到。

我试图修复你class:

class A:
    @staticmethod
    def _add(a, b):
        return a + b

    @classmethod
    def f_add(cls):  # valid
        return cls._add

    @classmethod
    def lambda_add(cls):  # valid
        return lambda x, y: cls._add(x, y)

    @staticmethod
    def lambda_arg_add(l=lambda x, y: A._add(x, y)):  # valid
        return l

    @classmethod
    def partial_add(cls):  # valid
        return partial(cls._add)

    @staticmethod
    def partial_arg_add(f=partial(_add)):  # TypeError: 'staticmethod' object is not callable
        return f

但是 partial_arg_add 会失败,因为在创建部分时 _add 还不可调用 :

class A:
    @staticmethod
    def _add(a, b):
        return a + b

    print(_add(1, 3))  # TypeError: 'staticmethod' object is not callable
class A:
    @staticmethod
    def _add(a, b):
        return a + b


print(A._add(1, 3))  # 4