3

私はAPIを書いていて、次のことを行うための最もPython的な方法は何だろうと思っていました。

私はさまざまなWeb呼び出しを行うための一連のメソッドを作成していますが、引数は主にポストデータのキーと値に変換されます。

私がこれまで書いてきた方法は、ほとんどこのようなものです。

def doSomething(self,param1,param2,param3):
    payload={"param1":param1,
             "param2":param2,
             "param3":param3}
    return self.request("do/something",payload)

これには、変更される可能性のあるパラメーター名を繰り返さなければならないという欠点がすでにありますが、このパターンはそれほど悪くはありません。

次のケースは、私がより良い方法を考えようとした理由です。この場合、呼び出しには4つのオプションの引数があります

def doSomethingElse(self,param1,param2=None,param3=None,param4=None,param5=None):
    payload= {"param1":param1}
    if param2:
        payload["param2"]= param2
    if param3:
        payload["param3"]= param3
    # ... etc ...
    self.request("do/something/else",payload)

私の最初の考えはこれを行うことでした:

def doSomethingElse(self,param1,**params):
    payload = {"param1":param1}
    payload.update(params)
    self.request("do/something/else",payload)

あるいは:

def doSomethingElse(self,**payload):
    self.request("do/something/else",payload)

2つ目は素晴らしくシンプルですが、デフォルト以外の引数なしでメソッドを呼び出すことができます。しかし、どちらの場合も、APIを使用するとメソッドの署名が失われ、ユーザーはパラメーターが何であるかを知りません(期待される署名をドキュメント文字列に書き込むことができることはわかっていますが、スペルミスのキーワードが送信されるのを防ぎたいです)。

私はこれを行うための素晴らしいpythonicソリューションが必要だと思っています、何かアイデアはありますか?

編集

私が十分に明確にしなかった重要な点は、引数が呼び出しの投稿データで送信されていることだと思います。最初の例のように、それらのキーだけが送信できるようにしたいのdoSomethingElseです。 tこれらの5つの名前付きパラメーター以外のものを送信します。

4

4 に答える 4

4

Pythonの方法は、関数のシグネチャではなく、関数を呼び出すときにパラメータに名前を付けることです。

def doSomething(self, **kwargs):
    self.request("do/something/else", kwargs)

doSomething(param1=3, param2='one', param3=4)
于 2012-06-29T19:12:27.100 に答える
1

このようなもの、おそらく:

def doSomethingElse(self, param1, **params):
    payload = {"param1": param1}
    for name, value in params.items():
        if value is not None:
            payload[name] = value
    self.request("do/something/else", payload)
于 2012-06-29T19:01:55.423 に答える
1

単純にどうですか

def get_payload(ldict):
    return {k:v for k,v in ldict.iteritems() if k != 'self' and v is not None}

class fred(object):
    some_class_var = 17
    def method(self, a, b=2):
        payload = get_payload(locals())
        print payload

これは

>>> f = fred()
>>> f.method()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: method() takes at least 2 arguments (1 given)
>>> f.method(2)
{'a': 2, 'b': 2}
>>> f.method(2, b=3)
{'a': 2, 'b': 3}
>>> f.method(5, b=None)
{'a': 5}
>>> f.method(2, b=3, c=19)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: method() got an unexpected keyword argument 'c'
>>> help(f.method)

Help on method method in module __main__:

method(self, a, b=2) method of __main__.fred instance

これはあなたの基準に一致すると思います。次のステップは、デコレータを使用して(おそらく、ラップまたはデコレータモジュールを使用して署名を保持する)、ペイロードが計算されて渡されるようにすることです@payloadが、それよりもはるかに優れているかどうかはわかりませんpayload = get_payload(locals())。この方法を使用locals()する場合は、最初に実行する必要があることに注意してください。

しかし、これは望ましくない核攻撃を防ぐための最善の方法ではないという気持ちを二番目に感じます。

于 2012-06-29T19:24:23.897 に答える
0

そのような関数がいくつかある場合は、次のように実行できます。

class Requester(object):
    def __init__(self, tobecalled, *allowed):
        self.tobecalled = tobecalled
        self.allowed = set(allowed)
    def __call__(self, otherobj, **k):
        for kw in k.iterkeys():
            if kw not in self.allowed:
                raise ValueError("unknown argument(s) given: %s" % kw)
        otherobj.request(self.tobecalled, **k)
    def __get__(self, outside, outsideclass):
        return lambda **k: self(outside, **k)

class Outside(object):
    def request(self, method, **k):
        print method, k
    do_one_thing = Requester("do/one/thing", 'param1', 'param2')
    do_nonsense = Requester("do/nonsense", 'param3')
    simple = Requester("simple")

o = Outside()
o.do_one_thing(param1=1, param2=2)
o.do_nonsense(param3=12)
o.simple()
try: o.do_one_thing(rparam1=1, param2=2)
except ValueError, e: print e
try: o.do_nonsense(gparam3=12)
except ValueError, e: print e
try: o.simple(whatever=12)
except ValueError, e: print e

ここでは何が起きるのですか?Requesterメソッドの役割を果たすオブジェクトを作成します。それを別のクラス(ここでは:)に入れるとOutside、呼び出されたオブジェクトの参照も取得するように呼び出すことができます。私がoutsideここで呼んでいるのは、今私が呼んでいる「アウターself」です。次に、関数と同じように、オブジェクト自体を呼び出すラムダを返します。そしてそこで、引数の妥当性がチェックされ、それが合格した場合は、" outside"のrequest()メソッドで呼び出しが行われます。

于 2012-06-29T21:52:51.067 に答える