0

これが私がやりたいことです:

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

この醜い回避策なしで、冒頭で説明したようなことを達成することは可能ですか? 注: 私は Python 2.5 程度の Jython にバインドされています (2.7 があることは知っていますが、アップグレードできません)。

4

6 に答える 6

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

次のように、関数を のデフォルト値として使用できます。ab

    def b(self, param=a):

aこれは、以前に定義されている限り機能しbます。ただし、関数aはバインドされたメソッドと同じではないため、self.a呼び出す前にバインドする必要があり、渡された callable をデフォルトのメソッドと区別する方法が必要aになるため、後者をバインドできますが、前者ではありません。これは明らかに、私が提案する比較的短くて読みやすいコードよりもはるかに厄介です。

于 2012-06-13T10:16:00.577 に答える
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です。)

于 2012-06-13T10:57:56.003 に答える
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.
于 2012-06-13T10:27:49.073 に答える
1

メソッド名を関数定義に入れることができます:

class Demo(object):

    def a(self):
        print 'a'

    def b(self, param='a'):
        if param:
            getattr(self, param)()

ただし、 がparamであるかどうかの値を持っているかどうかを確認する必要がありNoneます。このアプローチは、そのクラスの任意の関数の実行を許可するため、信頼できない入力には使用しないでください。

于 2012-06-13T10:18:46.877 に答える
1

私はlazyr答えが好きですが、この解決策の方が好きかもしれません:

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()
于 2012-06-13T10:23:01.510 に答える
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メソッド (またはメソッドになる関数) に関連付けられます。MethodBinders メソッドには、関連付けられset_defaultsたメソッドを呼び出すために使用される引数を指定できます。関連付けられたメソッドのバインドされていないメソッドをバインドし、関連付けられたメソッドを呼び出すために使用できる kwargs dict を返します。self

これで、このクラスを使用してデコレータを作成できます。

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 に新しく追加さgetcallargsinspectた . python2.7 および 3.1 の新しいバージョンでのみ使用できます。

于 2012-06-18T11:09:11.870 に答える