2013-02-22 21 views
11

静的メソッドはいつどのように使用されると思われますか?私たちはすでに、ファクトリメソッドとしてクラスメソッドを使用して、可能な限りオブジェクトのインスタンスを作成しないようにしました。つまり、クラスメソッドを代替コンストラクタとして使用するのはベストプラクティスではありません(Factory method for python object - best practiceを参照)。Pythonでの静的メソッドの使用 - ベストプラクティス

データベース内のエンティティデータを表すために使用されるクラスがあるとします。データがフィールド名とフィールド値を含むdictオブジェクトであり、フィールドの1つがデータを一意にするID番号であるとします。ここで

class Entity(object): 
    def __init__(self, data, db_connection): 
     self._data = data 
     self._db_connection 

__init__方法は、エンティティデータdictオブジェクトを受け取ります。私はID番号のみを持っており、Entityインスタンスを作成したいとします。最初に残りのデータを見つけて、Entityオブジェクトのインスタンスを作成する必要があります。私の以前の質問から、ファクトリメソッドとしてのクラスメソッドの使用は、おそらく避けなければならないことを立証しました。

上記は、何もしないか、または少なくとも代替手段がない場合はどうしたらよいかの例です。今私はそれがユーティリティメソッドのより多くのファクトリメソッドの有効な解決策であるように私のクラスメソッドを編集するかどうか疑問に思っています。つまり、次の例は、静的メソッドを使用するためのベストプラクティスに準拠していますか。

class Entity(object): 

    @staticmethod 
    def data_from_id(id_number, db_connection): 
     filters = [['id', 'is', id_number]] 
     data = db_connection.find(filters) 
     return data 


# Create entity 
data = Entity.data_from_id(id_number, db_connection) 
entity = Entity(data) 

また、スタンドアロン機能を使用してID番号からエンティティデータを見つける方が理にかなっていますか?

def find_data_from_id(id_number, db_connection): 
    filters = [['id', 'is', id_number]] 
    data = db_connection.find(filters) 
    return data 


# Create entity. 
data = find_data_from_id(id_number, db_connection) 
entity = Entity(data, db_connection) 

注:私は__init__メソッドを変更したくありません。以前は人々が私の__init__メソッドをこのようなものにすることを提案していましたが、エンティティデータを見つけるための101の異なる方法があるので、ある程度論理を分離しておくことを好むでしょう。理にかなっている?

+0

この質問の名前と導入文は、必要なコードを書く正しい方法を見つけようとするのではなく、言語機能を使用する理由から掘り下げているように思えます。私はそれがあなたが何をしているのかを言っているわけではありません。あなたの質問の実際のボディは、実際には有効な質問です。ちょうどあなたの言い回しについて少し考えてください。このようにして、良いPythonを書く人々のはるかに大きなプールではなく、言語機能を議論したい人からの回答しか得られないかもしれません。 – abarnert

答えて

6

あなたの最初の例が私にとって最も理にかなっています。Entity.from_idはかなり簡潔で明確です。

次の2つの例ではdataの使用を避けていますが、返される内容については説明していません。 dataを用いてEntityを構築する。 Entityの作成に使用されているdataについて具体的に説明したい場合は、メソッド名をEntity.with_data_for_idまたは同等の関数entity_with_data_for_idのように指定します。

findのような動詞を使用すると、戻り値の兆候を示さないため、かなり混乱する可能性があります。データが見つかったときに実行する関数は何ですか? (はい、私はstrfindメソッドを持って実現; ...それは、より良いindex_ofを命名されることはない。しかし、その後もindexあります?)それは古典のことを思い出す:私は常に考えてみる

find x

(a)システムについての知識がなく、(b)システムの他の部分についての知識 - 私はいつも成功しているとは言いません。

+1

"find"についての良い点。これは古いスコット・アダムスのテキスト・アドベンチャーのようなものです。なぜなら、主なパズルは汎用名の「使用」動詞にどの名詞を与えるのかを把握していたからです。 (Infocomゲームでは、「ロープをスプールから取り出し、ロープをフックに接続し、ロープを滑らせます」SAゲームでは、「SPE USE ROOEを使用します。 ) – abarnert

10

リンク質問への答えは、具体的には、この意見:

@classmethodはすべてSTDLIB-itertools.chain.from_iterable、日時を超える例は-thereある「代替コンストラクタ」を行うための慣用的な方法です。 .datetime.fromordinalなど

私はクラスメソッドの使用が本質的に悪いという考え方をどのようにして得たのか分かりません。私は実際にあなたの特定の状況でclassmethodを使用するというアイデアが好きです。これは、コードをフォローし、APIを使いやすくするためです。

代替はそうのようなデフォルトコンストラクタの引数を使用することです:

​​

私はあなたがしかし、もともと書いたクラスメソッドのバージョンを好みます。特にdataはかなり曖昧です。

16

いつ、どのように静的メソッドがPythonで使用されると思われますか?

グリブの答えはあまりありません。

無意味な答えは、あなたのコードを読みやすくするときです。


まずは、the docsに回り道をしてみましょう:Pythonで

静的メソッドは、JavaやC++で見られるものと同様です。別のクラスコンストラクタを作成するのに便利なバリアントについては、classmethod()も参照してください。

C++で静的メソッドが必要な場合は、Pythonで静的メソッドが必要です。

まあ、いいえ。

Javaでは、関数やメソッドだけがないので、静的メソッドのバンドルだけである疑似クラスを作成することになります。 Pythonで同じことをする方法は、フリー関数を使うことです。

これはかなり明白です。しかし、適切なクラスができるだけハードに見えるようにするのは良いJavaスタイルです。そのため、それらの擬似クラスを書くのを避けることができます。同じことは悪いPythonスタイルです。フリー関数を使用します。はるかに明らかではない。

C++にはJavaと同じ制限がありませんが、多くのC++スタイルはかなり類似しています。 (一方、「フリー関数はクラスのインタフェースの一部です」イディオムを内部化した「現代C++」プログラマーなら、「静的メソッドはどこにあるのか」というあなたの本能は、おそらくPythonにとってはまともです。)


しかし、第一原理からではなく、別の言語からこの時に来ている場合は、物事を見て簡単な方法があります:

@staticmethodは、基本的にはグローバル関数です。という機能があり、それがfoo_module.BazClass.bar()という綴りがあれば何らかの理由で読みやすくなる場合は@staticmethodにしてください。そうでない場合は、しないでください。それは本当にそこにあるすべてです。唯一の問題は、慣用的なPythonプログラマにとって読みやすいものの本能を築くことです。

もちろん、クラスへのアクセスが必要な場合は@classmethodを使用しますが、インスタンス代替コンストラクタは、ドキュメントの暗黙の通り、パラダイムケースではありません。 @classmethod@staticmethodをシミュレートするだけで明示的にクラスを参照するだけです(特にサブクラス化があまりない場合)。


最後に、あなたの具体的な質問になって:クライアントはこれまでIDでデータを検索する必要がある唯一の理由はEntityを構築することである場合

、それはあなたがさらすべきではありません実装の詳細のように聞こえますまた、クライアントコードをより複雑にします。コンストラクタを使うだけです。 __init__を変更したくない場合は、@classmethodを代替コンストラクタとして使用してください(Entity.from_id(id_number, db_connection))。

Entityの構造とは関係がないその他のケースでは、そのルックアップがクライアントにとって本質的に有用なものであれば、これはEntityクラスとは関係がないようです(少なくとも、同じモジュール内の他のもの)。だから、それを無料の機能にしてください。

関連する問題