Pythonのみならず他の言語でも関係すると思いますが、クラス変数の初期化についての質問です。
初期化を行う際、関数をもちいて値をセットしたい場合があります。
そういった場合、
関数内でセットしてしまうのか、関数によって返ってきた値をセットするのか、
どちらが良いのでしょうか?
Python
1class Example(): 2 def __init__(self): 3 self.X = setX() 4 5 def setX(): 6 return 1
Python
1class Example(): 2 def __init__(self): 3 self.X = 0 4 self.setX() 5 6 def setX(self): 7 self.X = 1 8
上の方が自然な感じもしますが、下のような書き方も見たことがあります。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
回答の前に、一つ用語の誤用を指摘します。
その変数Xは、クラス変数では無くインスタンス変数です。
クラス変数とはクラス宣言直下に置いた変数のことで、他言語のstaticメンバに相当します。
本題
関数内でセットしてしまうのか、関数によって返ってきた値をセットするのか、どちらが良いのでしょうか?
関数によって返ってきた値をセットする、一番目のコードの方法が一般的でしょう。
インスタンス変数を様々なメソッド内で生成すると、どんな属性があるのか管理しきれなくなります。
pylintも次のコードに対しデフォルトで警告を発します。W: の行です。
Python
1class Spam: 2 def method(self): 3 self.answer = 42
cmd
1>python -m pylint sample.py 2No config file found, using default configuration 3************* Module sample 4C: 1, 0: Missing module docstring (missing-docstring) 5C: 1, 0: Missing class docstring (missing-docstring) 6C: 2, 4: Missing method docstring (missing-docstring) 7W: 3, 8: Attribute 'answer' defined outside __init__ (attribute-defined-outside-init) 8R: 1, 0: Too few public methods (1/2) (too-few-public-methods)
SOでも同じような議論が交わされています。ぜひ目を通してみて下さい。
python - Instance attribute attribute_name defined outside init - Stack Overflow
投稿2019/11/11 15:47
編集2019/11/12 02:20総合スコア35668
0
ベストアンサー
個人的には前者をオススメしたいです。
ちなみに、前者のコードに誤りがあるので、修正します。
python
1class Example(): 2 def __init__(self): 3 # self.X = setX() <--- self が無いです。 4 self.X = self.setX() 5 6 # def setX(): <--- self が無いです。 7 def setX(self): 8 return 1 9 10example = Example()
副作用
なぜなら後者は「副作用」を持っているからです。
副作用というのは、属性(インスタンス変数、またはクラス変数)を変化させることです。
後者のコードは X
が1度 0
になってから 1
に変化しています。
これが「副作用」です。
最近プログラムを書くときに「副作用」を嫌傾向にある気がします。
「副作用」をあまり許さない言語として
Elixir や Elm などがあり、これを「関数型言語」と呼ばれるのを目にします。
なぜ「副作用」が嫌われる傾向にあるのかは、こちらに書きました。
PEP 8
ちなみに Python では PEP 8 というコーディング規約が使われていています。
本当にほとんど全ての Python を書く人はこれに従っています。
PEP 8 はキャメルケースではなくスネークケースです。
python
1class Example(): 2 def __init__(self): 3 # self.X = self.setX() 4 self.X = self.set_x() 5 6 # def setX(self): 7 def set_x(self): 8 return 1 9 10example = Example()
従わないといけない訳では無いのですが、
PEP 8 に沿っておいた方が無難かなという気がします。
staticmethod
staticmethod
を使うと self
を書かなくても動くようになります。
staticmethod
は使えるときには積極的に使うのが
副作用が無いことを明示している点で望ましいと個人的に感じています。
python
1class Example(): 2 def __init__(self): 3 # self.X = self.setX() 4 self.X = self.set_x() 5 6 # def set_x(self): 7 @staticmethod 8 def set_x(): 9 return 1 10 11example = Example()
投稿2019/11/11 17:32
編集2019/11/11 18:12総合スコア830
0
質問で "関数をもちいて値をセットしたい" とぼんやりとしか書かれていないこの部分の動機次第じゃないでしょうか。
特に、今 setX
というまったくよくない名前が付いているこの関数が一体何をするのか、それが明らかになる必要があると思います。
def caluculate_x_from_other_environments(): x = ... # 何かからxの初期値を計算する return x
という関数が外にあったり、あるいはメソッドとしてクラスの中にあるのなら
def __init__(self): self.X = caluculate_x_from_other_environments() # これは関数が外にある場合
が自然でしょう。
def set_x_and_initialyze_hogehoge(self, x) -> None: self.X = x ... # そしてx(self.X)を元に何か別のことをやる必要がある
というメソッドを想定するなら
def __init__(self): self.set_x_and_initialyze_hogehoge(1)
が自然でしょう。
初期化をどうするべきか? なんて考えても無駄です。
setX
がどういう関数であるべきか? を考えたら初期化の方はそれに応じて自然と決まるはずです。
本当に初期化だけが問題の争点であるなら、それはつまり初期化以外のタイミングでその処理をすることがないことが確実だという話になります。
ならば、それを関数にする必要はない、と答えます。
def __init__(self): self.X = 1
もしくは
def __init__(self): val = ... # なんか難しい処理 self.x = 1
とするべきだと思っています。
投稿2019/11/11 23:52
編集2019/11/11 23:58総合スコア11231
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/11/11 21:44
2019/11/12 02:20
2019/11/13 07:56
2019/11/13 08:05