[解決済み] モジュール関数 vs staticmethod vs classmethod vs デコレータなし。どのイディオムがよりパイソン的か?
質問
私はPythonを時々使っているJava開発者です。私は最近、偶然 この記事 この記事では、JavaプログラマがPythonを始めるときに犯しがちな失敗について言及しています。最初のものが私の目を引きました。
Javaでの静的メソッドはPythonのクラスメソッドに変換されません。確かに、それは多かれ少なかれ同じ効果をもたらしますが、クラスメソッドの目的は、実際にはJavaでは通常不可能なこと(デフォルトでないコンストラクタを継承するような)を行うことなのです。Java の静的メソッドの慣用的な翻訳は、通常、モジュールレベルの関数で、classmethod や staticmethod ではありません。(そして、静的な最終フィールドはモジュールレベルの定数に翻訳されるべきです。)
これはパフォーマンスの問題ではありませんが、このようなJavaの慣用的なコードで作業しなければならないPythonプログラマは、単にFoo.someFunctionとすべき時にFoo.Foo.someMethodとタイプすることでむしろいらいらすることでしょう。しかし、クラスメソッドの呼び出しは、staticmethodや関数の呼び出しにはない、追加のメモリ割り当てを含むことに注意してください。
それと、Foo.Bar.Bazの属性チェーンもタダではありません。Javaでは、これらのドット付きの名前はコンパイラによって調べられるので、実行時にいくつあってもかまいません。Pythonでは、ルックアップは実行時に行われるので、各ドットはカウントされます。(Pythonでは、quot;Flat is better than nested"は、パフォーマンスについてというよりも、quot;Readability counts" や "Simple is better than complex"に関連していることを思い出してください).
私はこれが少し奇妙であると感じました。 staticmethod にはこう書かれています。
Pythonの静的メソッドは、JavaやC++で見られるものと似ています。また、代替のクラスコンストラクタを作成するのに便利な変形として classmethod() を参照してください。
さらに不可解なのは、このコードです。
class A:
def foo(x):
print(x)
A.foo(5)
Python 2.7.3 では予想通り失敗しますが、3.2.3 では正常に動作します (ただし、Aのインスタンスに対してメソッドを呼び出すことはできず、クラスに対してのみ呼び出すことができます)。
つまり、静的メソッドを実装する方法は3つあり(classmethodの使用を含めると4つ)、それぞれに微妙な違いがあり、そのうちの1つは文書化されていないようです。これは、Pythonのマントラである 1 つの、そしてできればたった 1 つの -- それを行うための明白な方法があるべきです。 どのイディオムが最もPythonicなのでしょうか?それぞれの長所と短所は何ですか?
今のところ理解しているのはこんなところです。
モジュール機能。
- Foo.Foo.f()問題の回避
- 他の方法よりもモジュールの名前空間を汚染します。
- 継承がない
staticmethodです。
- クラスに関連する関数をクラス内部で保持し、モジュールの名前空間から除外します。
- クラスのインスタンス上で関数を呼び出せるようにする。
- サブクラスはメソッドをオーバーライドすることができます。
クラスメソッドです。
- staticmethodと同じですが、第一引数としてクラスを渡します。
通常のメソッド (Python 3のみ) :
- staticmethodと同じですが、クラスのインスタンスに対してメソッドを呼び出すことはできません。
私は考えすぎでしょうか?これは問題ないのでしょうか?どうか助けてください。
どのように解決するのですか?
最も簡単な方法は、メソッドが仕事をするためにどのような種類のオブジェクトを必要とするかという観点から考えることです。 メソッドがインスタンスにアクセスする必要がある場合は、通常のメソッドにします。 クラスへのアクセスが必要な場合は、クラスメソッドとします。 クラスやインスタンスにアクセスする必要がない場合は、関数にします。 staticmethodにする必要はほとんどありませんが、クラスへのアクセスが必要ないにもかかわらず、関数をクラスと一緒に(たとえばオーバーライドできるように)グループ化したい場合は、staticmethodにすることができるかもしれませんね。
モジュールレベルに関数を置くことは、名前空間を汚染しないことを付け加えます。 もし関数が使用されることを意図しているならば、名前空間を汚染しているのではなく、使用されるべきものとしてそれを使用しているのです。 関数は、クラスや他のものと同じように、モジュールの中の正当なオブジェクトです。 もし、そこにあるべき理由がないのなら、関数をクラスの中に隠す理由はないのです。
関連
-
[解決済み] 関数デコレータを作成し、それらを連鎖させるには?
-
[解決済み] staticmethodとclassmethodの違いについて
-
[解決済み] モジュールの関数名(文字列)を使って、モジュールの関数を呼び出す。
-
[解決済み] Pythonでシングルトンを作成する
-
[解決済み] なぜ[]はlist()よりも速いのですか?
-
[解決済み] Javaインターフェースでスタティックメソッドを定義できないのはなぜですか?
-
[解決済み] import文は常にモジュールの先頭にあるべきですか?
-
[解決済み】クラスのstaticmethodをクラス本体内で呼び出す?
-
[解決済み] Jupyter (IPython)ノートブックのセッションをpickleして保存する方法
-
[解決済み] Python Empty Generator 関数
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] staticmethodとclassmethodの違いについて
-
[解決済み] googletransがエラー 'NoneType' オブジェクトに 'group' 属性がない、と言って動かなくなった。
-
[解決済み] タプルのリストを複数のリストに変換するには?
-
[解決済み] Pythonのインスタンス変数とクラス変数
-
[解決済み] 文字列から先頭と末尾のスペースを削除するには?
-
[解決済み] Pythonでマルチプロセッシングキューを使うには?
-
[解決済み] PySparkでデータフレームのカラムをString型からDouble型に変更する方法は?
-
[解決済み] pycharmがタブをスペースに自動変換する
-
[解決済み] Pythonの辞書にあるスレッドセーフについて
-
[解決済み] Pythonでリストが空かどうかをチェックする方法は?重複