5

よく使う関数がまとまっているので、ライブラリにまとめたいと思います。ライブラリを書き始める前に、一部の関数の動作に影響を与える定数をどこに格納するかを考えていました。

ライブラリを使用する際に書きたかったことは次のとおりです。

import tools
tools.collect(object_a, object_b, mode=tools.collect.RECURSIVE)

一般的に言えば、関数が受け入れることができる定数は、関数自体に格納する必要があります。

これを実現するために、渡された属性を装飾された関数に割り当てるデコレーター関数を作成しました。

def attr_decorator(**attrs):
    def decorator(f):
        for k, v in attrs.iteritems():
            setattr(f, k, v)
        return f
    return decorator

このデコレータは次のように使用できます。

@attr_decorator(
    FLAT = 1 << 0,
    RECURSIVE 1 << 1,
)
def collect(a, b, mode):
    # ...

これはこれまでのところかなりうまくいきます。

しかし、デフォルトの引数はどうですか?

@attr_decorator(
    FLAT = 1 << 0,
    RECURSIVE 1 << 1,
)
def collect(a, b, mode=collect.RECURSIVE):
    # ...

モード引数のデフォルト値が格納されている時点でcollect関数が定義されていない (したがって装飾もされていない) ため、これは機能しません。

これは見栄えがよくありません

私が思いついた唯一の解決策は、ぎこちない構文になり、見栄えがよくありませんでした。デコレータ関数に、装飾される関数と同じ属性を与えています。

def attr_decorator(**attrs):
    def decorator(f):
        for k, v in attrs.iteritems():
            setattr(f, k, v)
        return f

    for k, v in attrs.iteritems():
        setattr(decorator, k, v)

    return decorator

これが読みやすくないことを認識するのに、天才は必要ありません。

collect_d = attr_decorator(
    FLAT = 1 << 0,
    RECURSIVE = 1 << 1,
)
@collect_d
def collect(root, callback, mode=collect_d.RECURSIVE):
    # ...

質問:

より良いアプローチを考えることができますか?私は本当に「装飾するステートメント」にとどまりたいと思っています.

4

2 に答える 2

1

定義されている関数への参照として、特別な変数を使用できます。

class Attr(object):
    def __init__(self, name): self.name = name

class Attributor(object):
    def __getattr__(self, x): return Attr(x)

_ = Attributor()

def attr_decorator(**attrs):
    def decorator(f):
        for k, v in attrs.iteritems():
            setattr(f, k, v)
        f.func_defaults = tuple(attrs[t.name] if isinstance(t, Attr) else t for t in f.func_defaults)
        return f
    return decorator    

@attr_decorator(
    FLAT = 1 << 0,
    RECURSIVE = 1 << 1,
)
def collect(a, b, mode=_.RECURSIVE, foo=123):
    print a, b, mode, foo

collect(100,200) # 100 200 2 123
于 2012-09-23T16:53:45.270 に答える
0

一般に、関数が受け入れることができる定数は、関数自体に格納する必要があります。

私はその意見に同意しません。これらの定数は、関数への外部インターフェイスの一部であり、呼び出し元によって使用されることを意図しています。それらを の一部として定義することの何が問題になっていtoolsますか?

COLLECT_RECURSIVE=0
COLLECT_NONRECURSIVE=1
COLLECT_OTHER=2

def collect(a,b,mode):
    pass

呼び出し側:

import tools
tools.collect(object_a, object_b, mode=tools.COLLECT_RECURSIVE)
于 2012-09-23T17:10:11.467 に答える