代码之家  ›  专栏  ›  技术社区  ›  intuited

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

  •  5
  • intuited  · 技术社区  · 14 年前

    我想这样做:

    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__ 你够傻吗 功能。这意味着它只有在作为对象属性引用时才以“正常”方式工作。有问题的对象是由 staticmethod() 装饰者在两者之间的作用 SillyWalk 你够傻吗 属性和最初用该名称定义的函数。

    这意味着为了使用 appraisal_method 从内部 SillyWalk.walk 它的呼叫者,我们必须

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

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

    None ,因为我想允许 传达不应调用该特定函数的信息。我想我还需要一些其他的价值,比如 False NotImplemented ,但似乎a)hackety b)恼人的是,必须为一些似乎可以非常简洁地表示为默认参数的内容编写额外的几行代码,以及其他冗余的文档。

    最好的办法是什么?

    3 回复  |  直到 14 年前
        1
  •  2
  •   Jason R. Coombs    14 年前

    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)
    

    请注意,默认的求值函数现在将是一个函数而不是一个方法,即使是足够愚蠢的,一旦类被创建(在代码末尾),它将被绑定为类方法。

    这意味着

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

    如果你真的想成为一个足够愚蠢的静态方法,你可以添加

        is_silly_enough = staticmethod(is_silly_enough)
    

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

        2
  •  2
  •   intuited    14 年前

    最后我编写了一个(un)包装函数,在函数定义头中使用,例如

    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

        3
  •  1
  •   Ryan Ginstrom    14 年前

    不知道我是否得到了你想要的东西,但是使用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