2011-08-22 4 views
10

私はリモートAPIにリクエストを行うクラスを持っています。私は電話の回数を減らすことができるようにしたいと思います。私のクラスのメソッドの中には同じAPI呼び出しを行うものがありますが(理由は異なっています)、キャッシュされたAPIレスポンスを共有することができます。Python - 複数のメソッドや多くのオプションのパラメータを持つ方がよいでしょうか?

API呼び出しを行う場合、メソッドにいくつかの必須パラメータがあるため、オプションのパラメータを使用するか、複数のメソッドを使用する方がPythonicであるかどうかは完全にはわかりません。

私はそれらを参照しているようにここでは、あなたは最高だと思いますか?

class A: 

    def a_method(item_id, cached_item_api_response = None): 
    """ Seems awkward having to supplied item_id even 
     if cached_item_api_response is given 
    """ 
    api_response = None 
    if cached_item_api_response: 
     api_response = cached_item_api_response 
    else: 
     api_response = ... # make api call using item_id 

    ... #do stuff 

またはこの:

class B: 

    def a_method(item_id = None, cached_api_response = None): 
    """ Seems awkward as it makes no sense NOT to supply EITHER 
     item_id or cached_api_response 
    """ 
    api_response = None 
    if cached_item_api_response: 
     api_response = cached_item_api_response 
    elif item_id: 
     api_response = ... # make api call using item_id 
    else: 
     #ERROR 

    ... #do stuff 

それともこれがより適切でしょうか?

class C: 
    """Seems even more awkward to have different method calls""" 

    def a_method(item_id): 
     api_response = ... # make api call using item_id 
     api_response_logic(api_response) 

    def b_method(cached_api_response): 
     api_response_logic(cached_api_response) 

    def api_response_logic(api_response): 
     ... # do stuff 

答えて

5

は通常、一つはメソッド/オブジェクトが1つのことを行うべきであると主張することができそれはうまくいくはずです。あなたのメソッドがコード内にますます多くのifsを必要とするパラメータがますます多くなる場合は、おそらくコードが複数のことをしていることを意味します。特に、これらのパラメータがまったく異なる振る舞いを引き起こす場合。代わりに、異なるクラスを持ち、それらにメソッドをオーバーロードさせることによって、同じ振る舞いが生成される可能性があります。あなたはまた、彼らはかどうかを決定するためにAPIの利用者のために、それは柔軟ながら応答およびキャッシュを検索する方法のロジックを分割することができます

class BaseClass(object): 
    def a_method(self, item_id): 
     response = lookup_response(item_id) 
     return response 

class CachingClass(BaseClass): 
    def a_method(self, item_id): 
     if item_id in cache: 
      return item_from_cache 
     return super(CachingClass, self).a_method(item_id) 

    def uncached_method(self, item_id) 
     return super(CachingClass, self).a_method(item_id) 

その方法:

たぶん、あなたのようなものを使用することができますキャッシング機能かどうか。

+0

編集していただきありがとうございますが、通常、継承の代わりに委譲を使用することをお勧めします。これは、クラスをより柔軟にするためです。 – Rickard

+0

これがあなたの意図でない場合は、変更して申し訳ありません。それはちょうどPythonの質問だったし、あなたのコードはPythonではありませんでしたので、私は最高の推測をしました - あなたの意図を反映するためにそれをロールバックまたは変更することを自由に感じてください。 (良い答えは何とか、すでに私の+1を持っています) – agf

2

class Bで使用されている方法に問題はありません。あなたが実際にitem_idまたはcached_api_responseのいずれかを含める必要が一目でそれがより明確にするために、私は最初のエラーチェックを入れます:メソッドを書くとき

class B: 

    def a_method(item_id = None, cached_api_response = None): 
     """Requires either item_id or cached_api_response""" 

     if not ((item_id == None)^(cached_api_response == None)): 
      #error 

     # or, if you want to allow both, 
     if (item_id == None) and (cached_api_response == None): 
      # error 

     # you don't actually have to do this on one line 
     # also don't use it if cached_item_api_response can evaluate to 'False' 
     api_response = cached_item_api_response or # make api call using item_id 

     ... #do stuff 
1

最終的には、それぞれの状況に応じて判断する必要があります。彼らは一貫性の意味を持つ、同様の情報

  • 単一の概念的なアイデアを渡されていても、

    1. 2つの完全に異なるアルゴリズムやアクションを、全く異なる意味で私は、これら2のどちらがより密接にフィットし、自分自身を求めるだろう入力に基づくニュアンスあり

    最初に近い場合は、別の方法を使用してください。 2番目が最も近い場合は、オプションの引数を使用します。追加の引数を渡さないように引数の型をテストすることによって、単一のメソッドを実装することさえできます。

  • 1

    これはOOのパターンです。

    class API_Connection(object): 
        def do_something_with_api_response(self, response): 
         ... 
    
        def do_something_else_with_api_response(self, response): 
         ... 
    

    インスタンスには2つのメソッドがあり、それらの間に状態を明示的に渡していますか?これらのメソッドはなぜ、モジュール内の裸の関数ではないのですか?

    代わりに、カプセル化を使用して、クラスのインスタンスにapiレスポンスを所有させることをお勧めします。例えば

    class API_Connection(object): 
        def __init__(self, api_url): 
         self._url = api_url 
         self.cached_response = None 
    
        @property 
        def response(self): 
         """Actually use the _url and get the response when needed.""" 
         if self._cached_response is None: 
          # actually calculate self._cached_response by making our 
          # remote call, etc 
          self._cached_response = self._get_api_response(self._url) 
         return self._cached_response 
    
        def _get_api_response(self, api_param1, ...): 
         """Make the request and return the api's response""" 
    
        def do_something_with_api_response(self): 
         # just use self.response 
         do_something(self.response) 
    
        def do_something_else_with_api_response(self): 
         # just use self.response 
         do_something_else(self.response) 
    

    self.responseを必要とする第1の方法は、それを計算しますので、あなたはキャッシングと、この応答は、複数のAPIリクエストを作成することなく、任意の順序で実行できる必要があります任意の方法を持っているし、他のすべての使用しますキャッシュされた値。うまくいけば、複数のURLやRPC呼び出しでこれを拡張することは容易に想像できます。上記のresponseのような戻り値をキャッシュする多くのメソッドが必要な場合は、メソッドのmemoizationデコレータを調べる必要があります。

    +0

    私は全体のコンセプトが気に入っていますが、コールごとに異なるパラメータがある場合、 'do_something'メソッドから' _get_api_response'メソッドに至るまでにいくつかの困難があります。しかし、まだ+1の価値がある。 –

    0

    キャッシュされたレスポンスは、Skittlesのバッグのように周囲に渡されないようにインスタンスに保存する必要があります。

    item_idはインスタンスごとに一意であるか、インスタンスが複数のクエリを作成できますか?それが複数あることができれば、私はこのようなものでいいと思う:

    class A(object): 
    
        def __init__(self): 
         self._cache = dict() 
    
        def a_method(item_id): 
         """Gets api_reponse from cache (cache may have to get a current response). 
         """ 
         api_response = self._get_cached_response(item_id) 
         ... #do stuff 
    
        def b_method(item_id): 
         """'nother method (just for show) 
         """ 
         api_response = self._get_cached_response(item_id) 
         ... #do other stuff 
    
        def _get_cached_response(self, item_id): 
         if item_id in self._cache: 
          return self._cache[ item_id ] 
         response = self._cache[ item_id ] = api_call(item_id, ...) 
         return response 
    
        def refresh_response(item_id): 
         if item_id in self._cache: 
          del self._cache[ item_id ] 
         self._get_cached_response(item_id) 
    

    そして、あなたはitem_idに関する最新の情報を取得する必要があります場合は、refresh_responseメソッドを持つことができます。

    関連する問題