这是我想要做的:
class demo(object):
def a(self):
pass
def b(self, param=self.a): #I tried demo.a as well after making a static
param()
问题显然是无法在函数声明行中访问该类。 有没有办法像c(++)一样添加原型?
目前我使用了一个丑陋的工作场所:
def b(self, param=True): #my real function shall be able to use None, to skip the function call
if param == True:
param = self.a
if param != None: #This explainds why I can't take None as default,
#for param, I jsut needed something as default which was
#neither none or a callable function (don't want to force the user to create dummy lambdas)
param()
如果没有这种丑陋的工作环境,那么有可能实现顶部所描述的东西吗?注意事项:我绑定Jython大约是python 2.5(我知道有2.7但我无法升级)
答案 0 :(得分:3)
简短回答:不。
我认为,如果您希望能够传递None
,True
等对象,最好的方法是创建一个自定义占位符对象,如下所示:
default_value = object()
class demo(object):
def a(self):
pass
def b(self, param=default_value):
if param is default_value:
self.a()
else:
param()
你可以使用功能a
作为b
的默认值,如下所示:
def b(self, param=a):
在a
之前定义b
时,这将有效。 但是函数a
与绑定方法self.a
不同,所以你需要先绑定它才能调用它,你需要一些区分传递的callable与默认方法a
的方法,以便您可以绑定后者但不能绑定前者。这显然比我建议的相对简短易读的代码更加混乱。
答案 1 :(得分:3)
不要告诉任何我告诉过你的人。
class demo:
def a(self): print(self, "called 'a'")
def b(self, param): param(self)
demo.b.__defaults__ = (demo.a,)
demo().b()
(在2.x中,__defaults__
拼写为func_defaults
。)
答案 2 :(得分:1)
您可以将方法名称放在函数定义中:
class Demo(object):
def a(self):
print 'a'
def b(self, param='a'):
if param:
getattr(self, param)()
但是,您仍需要检查param
是否具有None
的值。请注意,此方法不应用于不受信任的输入,因为它允许执行该类的任何功能。
答案 3 :(得分:1)
我喜欢lazyr' answer但也许你会更喜欢这个解决方案:
class Demo(object):
def a(self):
pass
def b(self, *args):
if not args:
param=self.a
elif len(args)>1:
raise TypeError("b() takes at most 1 positional argument")
else:
param=args[0]
if param is not None:
param()
答案 4 :(得分:1)
我也更喜欢lazyr的答案(我通常使用None
作为默认参数),但您也可以使用关键字参数来更明确地说明它:
def b(self, **kwargs):
param = kwargs.get('param', self.a)
if param: param()
您仍然可以使用None
作为参数,导致param
未被执行。但是,如果您不包含关键字参数param=
,则默认为a()
。
demo.b() #demo.a() executed
demo.b(param=some_func) #some_func() executed
demo.b(param=None) #nothing executed.
答案 5 :(得分:1)
我会再次回答这个问题,与我之前的回答相矛盾:
简答:是的! (某种程度上)
在方法装饰器的帮助下,这是可能的。代码很长,有点难看,但用法简短。
问题是我们只能使用未绑定的方法作为默认参数。那么,如果我们创建一个包装函数 - 一个装饰器 - ,它会在调用实际函数之前绑定参数,该怎么办?
首先,我们创建一个可以执行此任务的辅助类。
from inspect import getcallargs
from types import MethodType
from functools import wraps
class MethodBinder(object):
def __init__(self, function):
self.function = function
def set_defaults(self, args, kwargs):
kwargs = getcallargs(self.function, *args, **kwargs)
# This is the self of the method we wish to call
method_self = kwargs["self"]
# First we build a list of the functions that are bound to self
targets = set()
for attr_name in dir(method_self):
attr = getattr(method_self, attr_name)
# For older python versions, replace __func__ with im_func
if hasattr(attr, "__func__"):
targets.add(attr.__func__)
# Now we check whether any of the arguments are identical to the
# functions we found above. If so, we bind them to self.
ret = {}
for kw, val in kwargs.items():
if val in targets:
ret[kw] = MethodType(val, method_self)
else:
ret[kw] = val
return ret
因此MethodBinder
的实例与方法(或者更确切地说是将成为方法的函数)相关联。可以为MethodBinder
方法set_defaults
提供用于调用关联方法的参数,它将绑定关联方法的self
的任何未绑定方法,返回一个可用于调用相关方法的kwargs字典。
现在我们可以使用这个类创建一个装饰器:
def bind_args(f):
# f will be b in the below example
binder = MethodBinder(f)
@wraps(f)
def wrapper(*args, **kwargs):
# The wrapper function will get called instead of b, so args and kwargs
# contains b's arguments. Let's bind any unbound function arguments:
kwargs = binder.set_defaults(args, kwargs)
# All arguments have been turned into keyword arguments. Now we
# may call the real method with the modified arguments and return
# the result.
return f(**kwargs)
return wrapper
现在我们已经把丑陋放在了我们身后,让我们展示简单而美观的用法:
class demo(object):
def a(self):
print("{0}.a called!".format(self))
@bind_args
def b(self, param=a):
param()
def other():
print("other called")
demo().b()
demo().b(other)
这个食谱使用来自getcallargs
的python inspect
的新增内容。它仅适用于较新版本的python2.7和3.1。