Python 将membermethod设置为默认参数

Python 将membermethod设置为默认参数,python,jython,jython-2.5,Python,Jython,Jython 2.5,以下是我想做的: 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 fun

以下是我想做的:

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,大约是Python2.5,我知道有2.7,但我不能升级

我认为,如果希望能够传递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):

只要在b之前定义了a,这将起作用。但是函数a与绑定方法self.a不同,因此需要在调用它之前绑定它,并且需要某种方法来区分已传递的可调用方法与默认方法a,以便可以绑定后者而不是前者。这显然比我建议的相对较短且可读的代码要混乱得多。

您可以将方法名称放在函数定义中:

class Demo(object):

    def a(self):
        print 'a'

    def b(self, param='a'):
        if param:
            getattr(self, param)()
但是,您仍然需要检查param的值是否为None。请注意,此方法不应用于不受信任的输入,因为它允许执行该类的任何函数。

我喜欢,但您可能会更喜欢此解决方案:

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

我也喜欢lazyr的答案我通常使用None作为默认参数,但也可以使用关键字参数来更明确地说明:

def b(self, **kwargs):
    param = kwargs.get('param', self.a)
    if param: param()
您仍然可以使用None作为参数,从而导致param无法执行。但是,如果不包括关键字参数param=,它将默认为a


不要告诉任何人我给你看了这个

class demo:
    def a(self): print(self, "called 'a'")
    def b(self, param): param(self)
demo.b.__defaults__ = (demo.a,)

demo().b()
在2.x中,“默认值”拼写为func\u defaults。

我将再次回答这个问题,与我先前的回答相反:

简短回答:是的!有点

在方法装饰器的帮助下,这是可能的。代码很长,有点难看,但是用法又短又简单

问题是我们只能使用未绑定的方法作为默认参数。那么,如果我们创建一个包装函数(decorator),它在调用实际函数之前绑定参数,会怎么样呢

首先,我们创建一个可以执行此任务的助手类

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的实例与一个方法相关联,或者更确切地说,与一个将成为方法的函数相关联。MethodBinders method set_默认值可能被赋予用于调用关联方法的参数,它将绑定关联方法自身的任何未绑定方法,并返回可用于调用关联方法的kwargs dict

现在,我们可以使用以下类创建装饰器:

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)

这个方法使用了python的一个新的补充,来自inspect的getcallargs。它仅在python2.7和3.1的较新版本中可用。

这并不难看,但我会使用param=False,如果param为False,则使用它。除了getattr之外,这是一个很好且简单的解决方案。它允许客户端代码显式地请求默认行为,这是一件好事™.我想用None来表示没有函数调用,并有另一个deafult,这就是为什么我传入一些布尔值。但通常我认为没有一个是最好的option@ted:啊,我明白了。好吧,就上面的代码而言,您应该仍然能够将None作为参数传递。虽然我喜欢layzer的解决方案,但我想我会坚持我的解决方案。我接受这个答案,因为它完全符合我的要求,尽管这很难看,因为默认值不明显,我想这就是为什么你不想让我告诉任何人是否有其他原因,让我知道。另外,我想感谢您为Python2.5和3添加了正确的名称。很高兴知道一旦Jython赶上,该怎么做。请投票给我一些新的东西。顺便说一下,相当于_defaults__的2.x是im_func.func_defaults。然而,这种解决方案也存在一些复杂问题。参数callable已更改签名。OP的问题是param,现在是paramself。这是因为默认值仍然不是OP想要的,即self.a。现在是演示。a,a。因此,实际上,这与我在答案底部的建议是一样的——通过显式使用self作为参数来绑定方法。太棒了。我刚刚学到了更多关于python的知识。我不知道人们可以定义自己的装饰师+1.谢谢你的努力。不要为它将被找到的较旧的python代码而烦恼,但一旦我开始使用python 2.7,我将从中学习它的jython 2.7测试版已经发布了…@ted我已经从inspect.py查看了getcallargs的源代码,它看起来相当可移植。如果您只需将该函数复制到源代码中,就有可能在Python2.3中开箱即用。
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)