Using class/static methods as default parameter values within methods of the same class

荒凉一梦 提交于 2019-11-30 09:55:16

Maybe all you need is to use the function (and not the method) in the first place?

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)

Note that the default for appraisal_function will now be a function and not a method, even though is_silly_enough will be bound as a class method once the class is created (at the end of the code).

This means that

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

but

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

And you can call is_silly_enough with a walk argument, or call a walk instance with .is_silly_enough().

If you really wanted is_silly_enough to be a static method, you could always add

    is_silly_enough = staticmethod(is_silly_enough)

anywhere after the definition of walk.

I ended up writing an (un)wrapper function, to be used within function definition headers, eg

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

This actually seems to work, at least it makes my doctests that break without it pass.

Here it is:

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)

update:

I wrote doctests for the unstaticmethod function itself; they pass too. I'm still not totally sure that this is an actual smart thing to do, but it does seem to work.

Not sure if I get exactly what you're after, but would it be cleaner to use 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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!