3

私はデコレータを初めて体験しました。デフォルトで特定のシーケンスを返すターゲット関数の結果をフィルタリングするデコレータ クラスを作成しました。

class Filter(object):
    def __init__(self, id=None):
        self.id = id

    def __call__(self, func):
        def wrapper(*args):
            entity_ids = func(*args)
            result = {}
            for k, v in entity_ids.items():
                if self.id:
                    if '_' + str(self.id) in k:
                        result.update({k: v})
            return result
        return wrapper

次のような他のクラスのメソッドでデコレータを使用します。

class SomeClass(object):
    @Filter(id=None)
    def get_ids(*args):
        return result_sequence

クラスメソッドを呼び出すときにデコレータの引数を定義するにはどうすればよいですか:

>>>sc = SomeClass()
>>>sc.get_ids(*args)  # I want to pass the id kwarg for Filter here 

前もって感謝します

4

3 に答える 3

3

Filterクラス定義でデコレータを適用しました。引数を渡すのはそこです:id

@Filter(id=None)

id他の何かである必要がある場合は、その値をそこに渡す必要があります。

Filter()オブジェクトはその行で作成され、呼び出さ@Filter(id=None)れます。コードを次のように書き換えることもできます。

class SomeClass(object):
    def get_ids(*args):
        return result_sequence
    get_ids = Filter(id=None)(get_ids)

これは、Python がデコレータを処理するときに行うことです。

を置き換えるのはメソッドの戻り値であり、その時点でオブジェクトに引数を指定することはできなくなります。デコレータが返したネストされた関数になりました。Filter.__call__()get_idsFilter()SomeClass.get_ids()wrapper()

id装飾されたメソッドを呼び出すときに指定したい場合wrapper()は、(オプションの) 追加のid引数を受け入れるように署名を変更する必要があります。を既にサポートしているため、オプションのキーワード引数をサポートするためのキャッチオール引数を*args追加するしかありません。**kwargs

def wrapper(*args, **kwargs):
    id = kwargs.get('id', self.id)
    entity_ids = func(*args)
    result = {}
    for k, v in entity_ids.items():
        if id:
            if '_' + str(id) in k:
                result.update({k: v})
    return result

self.idここでは、直接使用する代わりにid、ラッパーへのキーワード引数がidデコレーター クラスに設定された値をオーバーライドします。

sc.get_ids(*args, id='foo')

ラップされた関数にもキーワード引数を渡したい場合があります。その場合、私は使用します:

def wrapper(*args, **kwargs):
    id = kwargs.pop('id', self.id)
    entity_ids = func(*args, **kwargs)
    result = {}
    for k, v in entity_ids.items():
        if id:
            if '_' + str(id) in k:
                result.update({k: v})
    return result

ここでは、残りのキーワード引数をラップされた関数に渡す前に、idキーワード引数が削除されます。

于 2013-10-18T09:52:57.490 に答える
2

マーティンの答えは網羅的です...またはほとんどです。装飾された関数を呼び出すときに「id」引数をオーバーライドできるようにしたい場合は、キーワード引数を使用してそれを行うことができます。

class Filter(object):
    def __init__(self, id=None):
        self.id = id

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            id = kwargs.get("id", self.id)
            entity_ids = func(*args)
            result = {}
            for k, v in entity_ids.items():
                if id:
                    if '_' + str(id) in k:
                        result.update({k: v})
            return result
        return wrapper

ただし、これは次のことを意味することに注意してください。 1. デフォルトをオーバーロードする場合は、キーワード引数として 'id' を渡す必要があります。とりあえず)

補足として (ここでは少し OT ですが...)、ラッパー関数の実装は多少改善される可能性があります。

        def wrapper(*args, **kwargs):
            id = kwargs.get("id", self.id)
            if not id:
               # no need to go further
               return {}

            id = "_%s" % id
            entity_ids = func(*args)
            result = dict(
                (k, v) for k, v in entity_ids.items()
                if id in k
                )
            return result
于 2013-10-18T10:32:43.727 に答える
0

ラッパーを変更する必要があります:

class Filter(object):
    def __init__(self, id=None):
        self.id = id

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            id = kwargs.get('id', self.id)
            entity_ids = func(*args)
            result = {}
            for k, v in entity_ids.items():
                if self.id:
                    if '_' + str(self.id) in k:
                        result.update({k: v})
            return result
        return wrapper

idこれにより、ラップされたメソッドを呼び出すときに代替値を与える機会が得られます。

class SomeClass(object):
    @Filter(id=None)
    def get_ids(*args):
        return result_sequence

Filterオブジェクトのメソッドは、追加のkwarg__call__を持つラッパーを返すようになりました。したがって、クラス定義時に指定されidた値をオーバーライドできます。id

sc = SomeClass()
sc.get_ids(*args, id='other')  # I want to pass the id kwarg for Filter here 
于 2013-10-18T10:16:05.617 に答える