我想做这样的事情:
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
的{{1}}属性和最初用该名称定义的函数之间放置的。
这意味着,要在 is_silly_enough
或其来电者中使用默认值appraisal_method
,我们必须< / p>
SillyWalk.walk
,而不只是致电appraisal_method.__get__(instance, owner)(...)
appraisal_method(...)
的方法。鉴于这些解决方案似乎都不是Pythonic™,我想知道是否有更好的方法来获得这种功能。我基本上想要一种方法来指定方法默认情况下应该使用在同一类范围内定义的特定类或静态方法来执行其日常例程的某些部分。
我不想使用appraisal_method
,因为我想允许None
传达不应该调用该特定函数的消息。我想我可以使用其他一些值,比如None
或False
,但似乎a)hackety b)烦人的是必须编写额外的几行代码,以及其他冗余的文档,对于看似可以非常简洁地表达为默认参数的东西。
最好的方法是什么?
答案 0 :(得分:2)
我最终编写了一个(un)包装函数,用于函数定义头文件,例如
def walk(self, appraisal_method=unstaticmethod(is_silly_enough)):
这实际上似乎有效,至少它使我的doctests在没有通过的情况下破解。
这是:
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
函数本身编写了doctests;他们也过去了。我仍然不能完全确定这是一个真正聪明的事情,但它似乎确实有用。
答案 1 :(得分: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)
请注意,appraisal_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)
在walk的定义之后的任何地方。
答案 2 :(得分: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