質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

6979閲覧

pythonのstaticmethodをコードの読みやすさだけのために使うべきか

MasatakaMiyoshi

総合スコア109

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

1グッド

2クリップ

投稿2016/05/30 04:45

編集2016/07/19 10:43

pythonのclass設計について質問します。

いま、例えばあるクラスFooを作ろうとしているときに、2パターンのコードを考えています。

Python

1class Foo(object): 2 def __init__(self, n): 3 self.x = n 4 self.z = 3 5 self.y = self.calc_y(x) 6 7 @staticmethod 8 def calc_y(x): 9 y = do_something(x) 10 return y 11

Python

1class Foo(object): 2 def __init__(self, n): 3 self.x = n 4 self.z = 3 5 self.set_y() 6 7 def set_y(self): 8 self.y = do_something(self.x)

①は、calc_yで使用する変数を明示しているので、クラス変数xの変更がこれに影響すること、変数zの変更はこれに全く影響しないことが明示されます。

しかし調べた限りでは@staticmethodは可能なら使わないほうが良いという記事が多く、その点では②にすべきであるように思えます。

実際のところ、どちらが良いのでしょうか?
また、それは何故でしょうか?

argius👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

"Flat is better than nested." です(Zen of Python より)。

python

1def calc_y(x): 2 y = do_something(x) 3 return y 4 5class Foo(object): 6 def init(self, n): 7 self.x = n 8 self.z = 3 9 self.y = calc_y(x)

staticmethod が良いかどうかの前に、flatな構造にすることを考えてみてください。

投稿2016/05/31 04:45

shimizukawa

総合スコア1847

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

MasatakaMiyoshi

2016/05/31 06:41

アドバイスありがとうございます。 Zen of Pythonの存在をすっかり忘れていたのですが、なるほどと思いました。 ところで、calc_y()は、たとえそれがFooのクラス変数を代入するときにしか呼び出されないとしても (つまり、Fooクラスに対する処理以外の場面では全く必要とされないことが予めわかっていたとしても) Fooの外で定義するべきでしょうか? また、逆にshimizukawaさんがstaticmethodの使用を検討する基準はどのあたりにありますか?
shimizukawa

2016/05/31 06:54

関数を分けるほどの内容なら、関数にします。関数をstaticmethodでメソッドにするよりは、クラス外の関数にします。外から呼び出して欲しくなければ _ を関数名の前に付けます。 最近はstaticmethod使わないですね。
MasatakaMiyoshi

2016/06/04 05:23

アンダースコアをつけるて関数を外に定義する方法を実際の自分のコードで試したところ、たしかにクラス内が見やすくなって可読性が上がりました。 また、インデントが下がって79文字制限の中で改行しなくて良い部分が増えたという意味でも助かりました。 とてもよい考え方ですね。今後も積極的に使っていこうと思います。
guest

0

ベストアンサー

一般的にどっちが良いというものではありません。

①は、calc_yで使用する変数を明示しているので、クラス変数xの変更がこれに影響すること、変数zの変更はこれに全く影響しないことが明示されます。

要はどう使うかなので、staticmethodで計算だけ分離しても、結局メンバ変数に代入するしかないのなら意味ないですよね。それに「全く影響しない」ことが明示される代わりに、メンバ変数へ副作用を与える以外の使い道を含ませてます(Fooのインスタンスが存在しなくても、何かに使う用途がある)。そういう使い方を外に提供することは、使う側に利するでしょうか、実際に使うでしょうか。
こういうことは説明用のコード(class Foo)では分かりませんので、実際のコードで検討してみてください。

言うまでもないと思いますが、設計というのはまずインターフェースの設計であって、中身の設計ではありません。使いやすいインターフェースを良しとするのが基本なので、実際に使う側のコードを書いてみて、どれが使いやすいか比べてみてはいかがでしょうか。「2パターンのコードを考えています」で最初に考えるべきは使う側のコードです。

# @staticmethod f = foo.Foo(10) f.y = f.cacl_y(something) # yへの代入しか使い道ないなら残念
# method f = foo.Foo(10) f.set_y(something)
# @property f = foo.Foo(10) f.y = something # @property の setter
# ただの関数 f = foo.Foo(10) f.y = foo.calc_x(something)

などなど。

投稿2016/05/30 10:52

sharow

総合スコア1149

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

MasatakaMiyoshi

2016/05/31 06:04

なるほど…結局、出来上がったものの可読性や簡潔さなどから総合的に判断するしかないのかもしれないですね。 今回自分が思いつなかったsharowさんの例についてもお聞きしたいのですが、クラス作成時には一度も定義しなかったクラス変数を後で代入する操作、例えば class Foo(object): pass foo = Foo() foo.x = 777 というような操作に、実践場面で出会ったことはありますか? そういう操作ができる以上使い道があるような気がするのですが、後でxを追加するより先にxを定義しておくほうが良いような気もします。 本題からやや逸れる話題ですが、あればぜひお聞きしたいです。 よろしくお願いします。
sharow

2016/05/31 09:05

たまーにあります、データベースのORMなどを使っていて仕方がなくクラスを使っているとき、それからOOP的なインターフェースでexportされてる共有ライブラリのPython版をctypesで作るとき・・とかです。それ以外の場合は、そもそもあまりクラスを書かないので出会いようがなかったりします。list/dict/set、namedtupleなどで間に合います。 Pythonでは「クラスを使おう」とは考えないで、「便利なオブジェクトとは何か」と考える方が向いてます。例えば有名なrequestsモジュールのget()関数で戻ってくるのはResponseオブジェクトですが、これはこうあってくれてありがとうって感じです。Responseオブジェクトはユーザーが直接インスタンス化するのではなく、リクエストに対するレスポンスの情報が入っていて、get()でそれを返してくれます。それには便利なメソッドやプロパティが用意されています。この場合はこれが使いやすいと感じます。使いやすさから考えていって、あるオブジェクトがクラスの振る舞いでしか実現できなければ、クラスにしましょう、そういう感じでいいと思いますよ。 Requests: 人間のためのHTTP: http://requests-docs-ja.readthedocs.io/en/latest/ Stop Writing Classes(英語) https://www.youtube.com/watch?v=o9pEzgHorH0
MasatakaMiyoshi

2016/06/04 05:29

回答ありがとうございます。 なるほど、一応使用されることはあるんですね…。 また、自分は確かに、とりあえずクラス作成という思考に偏っていたかもしれません。 今書いているコードの中にも、クラスを解除して問題なさそうな (解除したほうがよさそうな) コードがありそうに思えるので、修正を検討してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問