よく使う関数がまとまっているので、ライブラリにまとめたいと思います。ライブラリを書き始める前に、一部の関数の動作に影響を与える定数をどこに格納するかを考えていました。
ライブラリを使用する際に書きたかったことは次のとおりです。
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):
# ...
質問:
より良いアプローチを考えることができますか?私は本当に「装飾するステートメント」にとどまりたいと思っています.