5

短いが完全な要約

関数 (クラス ファクトリ) のユーザーが、関数を使用するときにグローバル インポートを挿入/上書きできるようにしたい (以下の理論的根拠のより長い説明)。しかし、渡すことができる約 10 の異なる変数があり、コードに多数の非常に反復的な行が追加されます。(確かに、呼び出しも複雑になります:P) 現在、私は次のようなことを行っています (これらすべてを単純化しただけです)。実行可能にするために、ダミー クラスを使用していますが、実際のスクリプトでは などを使用しますimport pkg1。これは、クラス ファクトリなどよりも明確で短いと考えました。

class Dummy(object): pass

pkg1, pkg2 = Dummy(), Dummy()
pkg1.average = lambda *args : sum(args) / len(args)
pkg2.get_lengths = lambda *args : map(len, args)


def get_average(*args, **kwargs):
    average = kwargs.get("average") or pkg1.average
    get_lengths = kwargs.get("get_lengths") or pkg2.get_lengths
    return average(*get_lengths(*args))

adjusted_length = lambda *args: map(len, args) + [15]
print get_average([1,2], [10, 4, 5, 6]) == 3 # True
print get_average([1,2], [10, 4, 5, 6], get_lengths=adjusted_length) == 7 # True

関連する SO の質問

このスタック オーバーフローの投稿: Modifying locals in Pythonは特に関連性があるようで、当初はローカル ディクショナリに保存してローカルを上書きしたかったのですが、(1) うまくいかなかったようで、(2) うまくいかなかったようです。考え。ということで、何か他に方法がないか検討中です。

これは有望に見えました ( Python で別のモジュールのグローバルにオブジェクトを追加する) が、モジュールと同じ方法で現在のファイルのグローバルにアクセスする方法がよくわかりません。(そして、この質問 - python: mutating `globals` to dynamic put things in scope - は、(最終的に)これを使用してクラスを定義しているため、実際には適用されません)。

すべてを exec ステートメントでラップできると思います (この投稿のように - python exec()のグローバルとローカル) が、それは面倒であり、エラー チェック/リンティングなどを行うのがはるかに難しいことを意味します。

だからここに私がしたいことがあります。(注: from pkg1 import averageANDを使用from pkg2 import get_lengths していましたが、例をより明確にしたかった (これを実行するには、上記の pkg1 と pkg2 をコピーする必要があります))

average = pkg1.average
get_lengths = pkg2.get_lengths

def get_average(*args, **kwargs):
    localvars = locals()
    for k in ("get_lengths", "average"):
        if kwargs.get(k, None) and kwargs[k] is not None:
            localvars[k] = kwargs[k]
    return average(*get_lengths(*args))

print get_average([1,2], [10, 4, 5, 6]) == 3 #True
print get_average([1,2], [10, 4, 5, 6], get_lengths=adjusted_length) == 7 # False, is 3

私の特定のユースケースの根拠

現在、動的に生成されたクラス ファクトリ (SQLAlchemy mixin として使用) を作成しようとしていますが、クラスのユーザーが代替コンストラクターを渡せるようにして、SQLAlchemy アダプターなどを使用できるようにしたいと考えています。

たとえば、Flask-SQLAlchemy は SQLAlchemy と同じインターフェイスを提供しますが、より多くの機能を提供するためにすべての SQLAlchemy オブジェクトをラップするカスタム オブジェクト/クラス ( db) を提供します。

4

1 に答える 1

2

デフォルト値で引数を使用して関数を渡すことができます。これは実際に行っていることですが、よりクリーンです。他の引数がある場合に対処しやすいため、lists代わりに単一の引数として使用しました。*argsに渡すには、リストをタプルで囲む必要がありますget_average

組み込み関数sortedはこのように動作するため、Python プログラマーにとって理解しやすいはずです。

get_average(lists, average=pkg1.average, get_lengths=pkg2.get_lengths):
    return average(*get_lengths(*lists))

print get_average(([1,2], [10, 4, 5, 6]))
print get_average(([1,2], [10, 4, 5, 6]), get_lengths=adjusted_length)

多くのキーワード引数がある場合は、それらをオブジェクトにパッケージ化できます。

class GetAverageContext(object):
    def __init__(self, average=pkg1.average, get_lengths=pkg2.get_lengths):
        self.average = average
        self.get_lengths = get_lengths

DefaultGetAverageContext = GetAverageContext()

def get_average(lists, context=DefaultGetAverageContext):
    return context.average(*context.get_lengths(*lists))
于 2012-07-30T01:48:36.327 に答える