使用类/静态方法作为同一类方法中的默认参数值

int*_*ted 5 python static-methods decorator default-value class-method

我想做这样的事情:

class SillyWalk(object):
    @staticmethod
    def is_silly_enough(walk):
        return (False, "It's never silly enough")
    def walk(self, appraisal_method=is_silly_enough):
        self.do_stuff()
        (was_good_enough, reason) = appraisal_method(self)
        if not was_good_enough:
            self.execute_self_modifying_code(reason)
        return appraisal_method
    def do_stuff(self):
        pass
    def execute_self_modifying_code(self, problem):
        from __future__ import deepjuju
        deepjuju.kiss_booboo_better(self, problem)
Run Code Online (Sandbox Code Playgroud)

这个想法是有人可以做的

>>> silly_walk = SillyWalk()
>>> appraise = walk()
>>> is_good_walk = appraise(silly_walk)
Run Code Online (Sandbox Code Playgroud)

还有一些神奇的机器学习正在发生; 最后一点对我来说并不是特别感兴趣,这只是我发现的第一件事,它是在函数上下文和调用者的角度来举例说明静态方法的使用.

无论如何,这不起作用,因为is_silly_enough它实际上不是一个函数:它是一个对象,其__get__方法将返回原始is_silly_enough函数.这意味着它仅在作为对象属性引用时以"正常"方式工作.有问题的对象是由staticmethod()装饰器放入SillyWalkis_silly_enough属性和最初用该名称定义的函数之间的函数创建的.

这意味着,为了appraisal_method其中一个 SillyWalk.walk 它的调用者中使用from 的默认值,我们必须要么

  • 打电话appraisal_method.__get__(instance, owner)(...)而不是打电话appraisal_method(...)
  • 或者将其指定为某个对象的属性,然后将该对象属性引用为我们调用的方法appraisal_method.

鉴于这些解决方案都不是特别Pythonic™,我想知道是否有更好的方法来获得这种功能.我本质上想要一种方法来指定一个方法默认情况下应该使用在同一个类的范围内定义的特定类或静态方法来执行其日常例程的某些部分.

我不想使用None,因为我想允许None传达不应该调用特定功能的消息.我想我可以使用其他一些值,比如FalseNotImplemented,但似乎a)hackety b)烦恼,必须编写额外的几行代码,以及其他冗余文档,似乎可以表达的东西非常简洁地作为默认参数.

最好的方法是什么?

Jas*_*mbs 2

也许您所需要的只是首先使用该函数(而不是方法)?

class SillyWalk(object):
    def is_silly_enough(walk):
        return (False, "It's never silly enough")

    def walk(self, appraisal_function=is_silly_enough):
        self.do_stuff()
        (was_good_enough, reason) = appraisal_function(self)
        if not was_good_enough:
            self.execute_self_modifying_code(reason)
        return appraisal_function
    def do_stuff(self):
        pass
    def execute_self_modifying_code(self, problem):
        deepjuju.kiss_booboo_better(self, problem)
Run Code Online (Sandbox Code Playgroud)

请注意,评估函数的默认值现在将是一个函数而不是一个方法,即使 is_silly_enough 在创建类后(在代码末尾)将被绑定为类方法。

这意味着

>>> SillyWalk.is_silly_enough
<unbound method SillyWalk.is_silly_enough>
Run Code Online (Sandbox Code Playgroud)

>>> SillyWalk.walk.im_func.func_defaults[0] # the default argument to .walk
<function is_silly_enough at 0x0000000002212048>
Run Code Online (Sandbox Code Playgroud)

您可以使用 walk 参数调用 is_silly_enough ,或者使用 .is_silly_enough() 调用 walk 实例。

如果您确实希望 is_silly_enough 成为静态方法,您可以随时添加

    is_silly_enough = staticmethod(is_silly_enough)
Run Code Online (Sandbox Code Playgroud)

walk 定义之后的任何地方。