5

我想做这样的事情:

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)

想法是有人可以做

>>> silly_walk = SillyWalk()
>>> appraise = walk()
>>> is_good_walk = appraise(silly_walk)

并且还会发生一些神奇的机器学习;这最后一点对我来说并不是特别感兴趣,它只是我想到的第一件事,作为在函数内上下文和从调用者的角度举例说明静态方法使用的一种方式。

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

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

  • 打电话appraisal_method.__get__(instance, owner)(...)而不只是打电话appraisal_method(...)
  • 或将其分配为某个对象的属性,然后将该对象属性作为我们调用的方法引用,就像我们调用的那样appraisal_method

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

我不想使用None,因为我想允许None传达不应调用该特定函数的信息。我想我可以使用其他一些值,例如Falseor NotImplemented,但似乎 a) 很麻烦 b) 不得不编写额外的几行代码以及其他冗余文档很烦人,因为它似乎可以表达非常简洁地作为默认参数。

最好的方法是什么?

4

3 回答 3

2

我最终编写了一个(取消)包装函数,用于函数定义标头中,例如

def walk(self, appraisal_method=unstaticmethod(is_silly_enough)):

这实际上似乎有效,至少它使我的文档测试没有通过就中断。

这里是:

def unstaticmethod(static):
    """Retrieve the original function from a `staticmethod` object.

    This is intended for use in binding class method default values
      to static methods of the same class.

    For example:
        >>> class C(object):
        ...     @staticmethod
        ...     def s(*args, **kwargs):
        ...         return (args, kwargs)
        ...     def m(self, args=[], kwargs={}, f=unstaticmethod(s)):
        ...         return f(*args, **kwargs)
        >>> o = C()
        >>> o.s(1, 2, 3)
        ((1, 2, 3), {})
        >>> o.m((1, 2, 3))
        ((1, 2, 3), {})
    """
    # TODO: Technically we should be passing the actual class of the owner
    #         instead of `object`, but
    #         I don't know if there's a way to get that info dynamically,
    #         since the class is not actually declared
    #         when this function is called during class method definition.
    #       I need to figure out if passing `object` instead
    #         is going to be an issue.
    return static.__get__(None, object)

更新:

unstaticmethod我为函数本身编写了文档测试;他们也通过了。我仍然不能完全确定这是一件真正明智的事情,但它似乎确实有效。

于 2010-06-21T11:20:46.877 回答
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)

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

这意味着

>>> SillyWalk.is_silly_enough
<unbound method SillyWalk.is_silly_enough>

>>> SillyWalk.walk.im_func.func_defaults[0] # the default argument to .walk
<function is_silly_enough at 0x0000000002212048>

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

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

    is_silly_enough = staticmethod(is_silly_enough)

步行定义之后的任何地方。

于 2010-06-21T12:13:45.037 回答
1

不确定我是否得到了你想要的东西,但使用 getattr 会更干净吗?

>>> class SillyWalk(object):
    @staticmethod
    def ise(walk):
        return (False, "boo")
    def walk(self, am="ise"):
        wge, r = getattr(self, am)(self)
        print wge, r


>>> sw = SillyWalk()
>>> sw.walk("ise")
False boo
于 2010-06-21T10:21:43.517 回答