44937


Pythonのコードについての質問です。

コード例）  
・クラス定義

[code]

    class Orange:
        def __init__(self,w,c):
            self.weight=w
            self.color=c
            self.mold=0
            print("Created!")
    
        def rot(self,days,temp):
            """temp(温度)は摂氏"""
            self.mold=days*temp
    
[/code]

・インスタンスの利用例

[code]

    orange=Orange(200,"orange")
    print(orange.mold)
    
    orange.rot(10,37)
    print(orange.mold)
    
[/code]

①__init__は、どういう働きをしているのか。  
（初期化・・・といっても必要性がわかりません・・・）

②__init__の引数selfの必要性が参考書を見てもよくわからない。  
（これは、次のインスタンス変数を定義する際のself変数とは別物ですよね？）

③試してみると__init__内で定義していない変数（試したのはコード５行目のmold）は、後で自分で定義したメソッド内（rot）で変数として使えなかったが、なぜ？（これはたぶん①がわかってないからだと思います）

以上３つが疑問点です。よろしくお願いいたします。


CC BY-SA 4.0
2018-06-20T12:35:26.093
44922
2018-06-21T06:08:47.757
2018-06-20T14:17:35.307
29012
question
python
Pythonのクラスのスイート部分の__init__当たりの質問です。


私の理解している範囲ですが書きます。

> ①__init__は、どういう働きをしているのか。  
>  （初期化・・・といっても必要性がわかりません・・・）

**１** ．`__init__`は、初期化です。文字通りですが答えになっていないので、具体例を言います。  
猫は生まれた時から口を持っており、ニャーとなきます。しっぽをもっています。せまいところがすきです。  
  
クラスはオブジェクト指向なので、これと並行して考えることができます。  
あなたは猫でもなく、犬でもなく、あなた自身の、「物」を作ることができます。  
猫の創造主ならぬ、その「物」の創造主です。  
ですから、その「物」には、最初から備わっている状態を定義してやらねばなりません。

私はRPGゲームをこさえたいと思ってプログラミングを始めた人なんですが、

[code]

    　self.hp = 10
      self.attack = 5
      self.guard = 3
    
[/code]

とか、ゲームを始める最初から備わっているものがあり、逆にこれが最初からなければ、  
RPGとしては成り立たないというものがあります。  
これを決めるのも初期化のプロセスなのですが、だからといって最初から備えなければならないという ことばかりではありません。  
後で`self.hp = 10`と定義して使うにしてももちろんいいのです。  
第一章は物語形式で、ステータスは全く関係なく話が進み、第二章からステータスが必要となるときに、追加するようなプログラムを書くことも可能です。  
しかし、`self.hp = 10`という物自体が定められていないと、その後レベルアップしたときに、`self.hp +=
5`ななどとして、レベルアップの効果を反映するにあたり、`self.hp =
10`が定義されていないので、ヒットポイントが挙げられないはおろか、敵と戦うとき、何を体力としていたのかがないので、不死身のキャラクターという事になろうかと思います。（最初から設定しておいても、何の問題もないはずですので、私だったら定義しておきます）  
初期化は、設計者が、何をあらかじめ初期状態としてセットしておくかという事であるので、あなたご自身で考え、設計されればよいのです。  
「物」は、かならず初期状態を持ちますから、オブジェクト指向も、その考え方をとっていると思っていいんじゃないでしょうか。  
私たち人間もやはり初期状態を持っています。白人は、`self.skin = white`,黒人は`self.skin =
black`、我々日本人は、`self.skin = yellow`といわれますね。  
変わった着眼かもしれませんが、「方向」を持っています。前と後ろ、横。前と後ろが一緒になってしまうと、背中と背中がくっついたような人間になるのでしょうか。ほりさげていくと、人間自体の構成（赤ちゃんから備わっているものをすべて列挙することになる。）RPGでも、ドラゴンクエスト１でないかぎり、`self.direction`なるものを初期化しているとおもわれます。  
ちなみに肌は日に焼けて変化しますし、逆に白くなることもあります。赤くなることもあります。黒人さんはあまりかわらないでしょうが、それは見た目だけで、実際は若干、より黒く、より白くなっているかもしれません。

* * *

> ②__init__の引数selfの必要性が参考書を見てもよくわからない。  
>  （これは、次のインスタンス変数を定義する際のself変数とは別物ですよね？）

**2** ．メモリに読み込むかどうか、参照ルートをどのようにするかを決めるためのものです。  
確かに、初期化をする際に、`self`なしで定義することもできます。しかし、ローカル変数扱いになり、その名前空間でしか使用することはできません。初期化コードが実行された後、直ぐにつかえなくなるんじゃなかったかなと思います。(初期化はたいてい一度だけですから。）一度メモリに読み込ませると、後はいらないというコードの場合は、`self`を使わなくてもいいのです。主に、必要のない情報になるものなので、メモリ節約術で、そういうことがされます。  
`initial_bonus_hp = initial_bonus_points`#引数より  
`self.hp += initial_bonus_hp`  
もう`self.hp`の値は書き換わったので、`initial_bunus_hp`の変数はもうつかわないし、後で参照する予定もないから、いらない。`self.hp`は後でたくさん参照予定。（ゲームクリア状況で、`bonus_points`がげーむ開始から利用可能になるなど。）

`self`は文字どおり、そのオブジェクト自身が自分を参照できるということです。そのインスタンスにとって、参照可能な変数とでもいえるでしょうか。  
インスタンスを生成したとき、具体化個別化します。  
`class Neko:`  
というクラスを作り、  

[code]

    neko1 = Neko()
    neko2 = Neko()
    
[/code]

としてしまえば、`neko1`,`neko2`は全く別のオブジェクトで、共通の情報を持つだけということです。クローン猫ですね。自身を参照できるので、`neko1.nakigoe`
と打てば、ニャーと帰ってきます。もし、`class Nenneko`という別のクラスを作り、  
`neko3 = Nennneko()`  
としておき、あらかじめその中の、`self.nakigoe = "ミャー"`としておけば、  
`neko3.nakigoe`
を打つと、ミャーと帰ってくるはずです。もし、`self.`をはずし、`nakigoe`だけを`__init__`内で定義すれば、エラーが返ってきます。  
self.としていたものが、こうしてインスタンス化したときに、参照可能となるのです。

初期化はあくまでも初期化です。`self.hp`の値を、後で書き換えることができるように、  
`self.nakigoe`も、大人になったとすれば、`self.nakigoe = ングニォォォォ`とかになる  
かもしれません。これを、

[code]

    def koegawari(self,nakigoe = ングニォォォォ):
        self.nakigoe = nakigoe
    
[/code]

としておけば、後で、最初のなき声から、この鳴き声に、変更することができます。引数に好きな泣き声を入れ込めば、その鳴き声になりますし、連続鳴き声変化を起こすことも可能でしょう。  
とすれば、場面場面で、`self.nakigoe`はよびだされていることになり、それだけ、参照の機会はおおいのです。  
初期化は**「後で変化させたいあるいは参照したい変数の、基点となる変数だ」**と考えておけばいいのではないでしょうか。逆に、その物を構成するうえで、絶対に一度は必要となる変数であり、設計者としてそれを入れ込むタイミングは様々なものの、やはり何かの基点となる変数だ。」とでもいえましょうか。変化するかどうかは、そのものの性質によります。  
  
  
  
多くは最初から入れ込んでおけば楽なので、（後でコードを追加するコードをかくよりは、短くおさまるとおもいます）こういうことがされているのだということ。  
コードの可読性がぐっと高まり、保守などが容易になること。（散らばって追加されるとどこで  
何が追加されるのかわかりにくくなる。分散する必要性が薄い）。  
自分がコードを書く時も、その「物」自体を理解しておけば、`self.age`という変数は  
はあるはずだ。ということが、覚えていなくても連想可能になるはずです。  
私は`Qt`を使っているのですが、クラスばかりの世界です。`Qt`の強みの一つとして、このコードはあるはずだと、初学者でも連想可能なメソッドが多数用意されていることで、1000を超えるメソッドがあっても、割と類推できます。  
その「物」自体を、いかに理解しているかで、初期化要素の把握のされ方は違ってくるとおもいます。きれいなコードは後で思いついたように追加せず、最初から最後まで使うコードだから初期化しておく。だから、クラスを作成するには、事前の設計と構想が大切と言われています。  
（現実には後でおもいつくことが多いと思われ・・・）  
おとなになれば、ということなので、

[code]

    def koegawari(self,nakigoe = ングニォォォォ):
        if self.age > 3:
            self.nakigoe = nakigoe
    
[/code]

としてもOKです。もちろん、`self.age`も、初期化されていたことが前提です。

* * *

>
> ③試してみると__init__内で定義していない変数（試したのはコード５行目のmold）は、後で自分で定義したメソッド内（rot）で変数として使えなかったが、なぜ？（これはたぶん①がわかってないからだと思います）

**3**.初期化コードで、`self.mold`が定義されていなくとも、`self.rot`メソッドで、`self.mold`に、`days*temp`の値がはいったはずです。初期化で`self.mold`をセットしておかなかったとしても、`self.mold
= days*temps`で、`self.mold`が、その時につくられます。  
質問文には、`self.mold`を初期化しておかなければ使えなかったと書かれていますが、私も今もう一度確認したところ、使えました。  
これはまさに、後から変数を追加したケースですね。  
おそらく、使えないとおもってしまったのは、

[code]

    def rot(self,days,temp):
          self.mold = days*temp
    
[/code]

とコードに書いたときに、あっ！もうここで私`self.mold`定義したやん。じゃあ、もう`self.mold`はつかえるはずやん。とでもおもわれたのかもしれません。  
この場合、`self.rot(3,10)`などと、一度呼び出した時に、初めて`self.mold`という変数が、参照可能になります。

`__init__`は、`orange=Orange(200,"orange")`というコードが実行されたときに、最初に実行されるコードのことです。

ですから、`orange=Orange(200,"orange")`というコードが実行された直後には、`orange.mold`とよんだとしても、そんな変数は定義されていないとエラーがかえってくるはずです。その間隙に呼び出してしまったから、つかえなかったんじゃないかなと思います。  
もう一度試してみてください。（なお、お使いのエディタによっては、前の変数を記憶している場合があり、こうした思考錯誤を、さらに誤解させる場合があります。カーネル再起動などをおこなったり、エディタ自体を一度再起動して、試すのがいいかもしれません。）

初期化の定義がどうであれ、変数をいつ入れ込むかどうかは、設計者の自由です。スキルが上がれば、何を最初に入れておき、何を後から追加するかは、次第に判断できるようになるのではないかなと思います。

ちなみに、クラスメソッドという、クラスをインスタンス化する前の共通のメソッドもあります。

[code]

    class Orange(self,w,c):
        orange = "バレンシアオレンジ"
        def __init__ ....
    
[/code]

`Orange.orange`で、インスタンスを生成しなくても、参照できます。  
繰り返しますが、`Orange.weight`などは、`orange=Orange(200,"orange")`として、インスタンスを生成したときに、はじめて作られるものですから、呼び出せません。  
こういう使い方をする人はおそらくいないんじゃないかなと思いますが、  
`Orange(200,"orange").weight`として参照することもできます。コードは上から下、左から右に評価されるためです。  
初期化とは  
1.インスタンス生成時に呼び出されるコード  
2.どんな変数を初期化するかは設計者次第。何を作るのかという、オブジェクトによって制限を受けるはず。  
3.後で追加することも可能だが、これは厳密には初期化とはいわない？。(基点となる変数を定めるということが初期化なんだととらえれば、いつ追加してしても、その変数にとって、それが初期化だといえる。たしかに,`a
= 5`これで`a`を初期化できますという表現があったような。）  
変化の基点となるとはいえ、変化させなくてもいいし、ずっと固定化ということももちろんあるはずです。

4.あまり厳密にかんがえる必要はなく、最初から完璧にしあげようとしなくてもいいかも。  
ただ、後で必要となったときに色々なところで参照し、変更を加える要素だから、最初が肝心なのは確か。時間をかけるべきところではあるが、行動してみて初めて気づくこともあり、どちらがいいとはいえない。こういうときに、いかにわかりやすい名前付けをしておくかで、機能追加やバグ取も行いやすくなるかな。`python`が保守性を重視する理由の一つだともいえる？難しいですよね。  
5．インスタンス化し、個別化する前の、そのものにとっての共通項を抽出するもの。

[code]

    character1 = Character(hp=10,mp=5,attack=3,.....)
    character2 = Character(hp=30,mp=0,attack=10,.....)
    
[/code]

厳密に言うとそうではないということもありますし、違うと言われる箇所もあるかもしれませんが、自分はだいたいこんな感じで理解しています。実際これでつくれているんで、いいかなとかｎんがえてたり。

* * *

4.  
さいごに、`self.mold`を、あえて`def
rot`の中で書くおそらく（自分の経験上最大の）メリットを書きます。それは、インスタンス生成時にかかる実行時間を減少できるということです。  
あなたが、Orangeというクラスのインスタンスを100個作りたいとしましょう。  
すると、Orangeは、それぞれ100回初期化され、それだけ__init__以下のコードが実行されます。すると、__init__内のコードが多ければ多いほど、読み込む時間が増えていきます。  
  
私は`Qt`を利用しているので、`Qt`で一番恩恵があったのですが、100個のボタンを作ったとします。ボタン1つを、クリックしたときに、初期化の時にくわえたかった機能を追加するようにすれば、最初から初期化したのと同じことになり、ユーザーが使いたいものをクリックした時に、その使いたいものごとに、初期化されるので、あたかも最初から初期化されていたような状態を作ることが出来ます.  
  
RPGだと、一度に将来登場する人物を、ゲーム開始時に全て読み込むよりは、町にはいるときや、イベント発生時点で読み込むようにすれば、それ単独の時間は、コンピューターなので、一瞬で済むと言った具合です。こうすれば、メモリの節約にもなり、初期化スピードも削減でき、パフォーマンスがぐっと向上します。python使いは実行速度で悩むことがおそらく一度はあるんじゃないかとおもいますので、覚えておくといいでしょう。pythonに限りませんけどね。  
ですから、初期化という言葉にこだわらなくてもよく、ただ、インスタンス生成時に実行されるコードがそれだ。何を入れ込むかは何を作るかによる。コーディングやメモリ効率にもよる。ということなので、あまり深く考えなくてもいいかもしれません。  
  


CC BY-SA 4.0
2018-06-21T03:25:25.640
44937
2018-06-21T05:07:15.347
2018-06-21T05:07:15.347
24284
24284
44922
answer


### `__init__` の必要性

オブジェクト指向プログラミングにおいて、あるオブジェクトのフィールドは、ある種の一環した値を取ることが期待されます。

Orange
は、おそらく果物のオレンジをどのように管理したかによってどのような品質状態になるかをモデル化したクラスだと考えられます。なので、たとえば次のような使用例が考えられます。

Q. オレンジを 10 日間 30度 で、 その後に ５日 20度で保管した。黴具合はいくらか。

A.

[code]

    class Orange:
        def __init__(self):
            self._mold=0
    
        def rot(self,days,temp):
            """temp(温度)は摂氏"""
            self._mold += days*temp
    
        def getMold(self):
            return self._mold
    
    orange = Orange()
    
    orange.rot(10, 30)
    orange.rot(5, 20)
    
    print(orange.getMold())
    # => 400
    
[/code]

このような使い方をした場合、 Orange クラスを使うユーザーは、 orange._mold
に直接アクセス、特に代入することはしません。むしろ、それをやってしまうと、 Orange クラスがメソッドによって公開していた _mold
フィールドに関する良い性質 (これまで呼ばれた rot に応じたかび度合い)
が、壊れてしまいます。蛇足ですが、このようなユーザーが直接参照してほしくないフィールドは、 python
ではアンダースコアから始まる変数によって初めることで示すという規約があります。

オブジェクト指向によってメンバーをまとめあげる大きなメリットの一つとして、このように、メンバー変数が満たしてほしい性質を、そのクラス設計者が想定する使い方すなわち、大体においてその公開されているメソッドを、呼び出していった場合において、常に満たすようにするということがあります。

オブジェクトを新しく作成したときに、 `__init__`
に何も書かないと、それはクラスのフィールドが満たしてほしい性質を満たせません。自分が作成した例で言うならば、 「_mold はこれまで呼ばれた rot
に応じた黴度合いを数値で表す」です。 (何も書かないと、 None になっていると思います。これだとなんか 0
と同じ感じではありますが、例えば、最初の黴度合いは 10 からスタートする、といったような性質が今扱いたい Orange
モデルにあったとすれば、やはり初期化は欲しくなります。)

### self

python では、すべてのメソッドはその第一引数に、そのメソッドを呼んでいる主体のオブジェクトを引数に取る、という言語設計です。たとえば ruby
とかではこれは暗黙的に `self` にバインドされていますが、オブジェクト指向のメソッドの中であれば確実に存在しているはずの参照です。

### 初期化

python において、 `__init__`
は、「オブジェクトがメモリの上に作成されたときに、最初に必ず呼ばれるメソッド」であって、それ以上でも以下でもありません。

python は、言語設計により、クラスによって暗黙的に参照可能な変数というのはほとんど存在していないです。ほぼほぼ def
でメソッドを定義したときにバインドされる変数たちぐらいです。 (たぶん。あんまり python くわしくないですが)

python におけるインスタンス変数とは、 `オブジェクト.フィールド名称` で参照、 `オブジェクト.フィールド名称 =`
で代入される、オブジェクトにひもづいたフィールドだけです。


CC BY-SA 4.0
2018-06-21T05:42:37.643
44942
2018-06-21T05:42:37.643
754
44922
answer


> ①__init__は、どういう働きをしているのか。  
>  （初期化・・・といっても必要性がわかりません・・・）

コード例で、クラス定義を`__init__`を使わずに、次のように書いて

[code]

    class Orange:
        def initialize(self,w,c):
            self.weight=w
            self.color=c
            self.mold=0
            print("Created!")
    
        def rot(self,days,temp):
            """temp(温度)は摂氏"""
            self.mold=days*temp
    
[/code]

次のように使用すれば、同じことになります。

[code]

    orange=Orange()
    orange.initialize(200,"orange")
    print(orange.mold)
    
    orange.rot(10,37)
    print(orange.mold)
    
[/code]

でも、毎回2行書く必要があるのであれば、`__init__`を使った方が便利ですよね。

> ②__init__の引数selfの必要性が参考書を見てもよくわからない。  
>  （これは、次のインスタンス変数を定義する際のself変数とは別物ですよね？）

コード例では、普通の変数を使っていないのでわかりにくいのですが、次のように普通の変数が必要な場合を考えると、普通の変数とインスタンス変数を区別する必要があるというのは理解できるのではないかと思います。これで`n`や`i`がインスタンス変数になってしまうと他のメソッドにある`n`や`i`の値を変えてしまいます。

[code]

    def __init__(self,w,c):
        n = w * 2 + 30
        self.weight= 0
        for i in range(n)
            self.weight += i * i
        self.color=c
        self.mold=0
        print("Created!")
    
[/code]

Java等他の言語では、インスタンス変数に`this`をつけて区別するものが多いです。

次に`__init__(self)`というように引数selfがなぜ必要なのかというと、Pythonの文法でそうなっているからだというのが回答だと思います。では、Pythonの文法でなぜselfを引数に必要としているかについては、Pythonの開発者であるグイド・ヴァンロッサム氏が「[Why
explicit self has to stay](http://neopythonic.blogspot.com/2008/10/why-
explicit-self-has-to-stay.html)」というプログで説明しています。（日本語訳「[和訳
なぜPythonのメソッド引数に明示的にselfと書くのか](https://coreblog.org/ats/translation-of-why-
explicit-self-has-to-stay/)」）

>
> ③試してみると__init__内で定義していない変数（試したのはコード５行目のmold）は、後で自分で定義したメソッド内（rot）で変数として使えなかったが、なぜ？（これはたぶん①がわかってないからだと思います）

__init__内で定義していないインスタンス変数を他のメソッド内で使うことは可能です。


CC BY-SA 4.0
2018-06-21T06:08:47.757
44943
2018-06-21T06:08:47.757
15171
44922
answer