OOP

About OOP

Key Concepts

従来の(オブジェクト指向でない)考え方

  • プログラムには変数を含む記述がある
  • 機能(Function)はタスクに従って上述のデータに働きかける
  • Functionの呼び出しに応じてデータはあちこちに通ってゆく

オブジェクト指向の考え方では

  • データと機能が組み合わさってオブジェクトと呼ばれる

list型を用いた例

  • xは1と5と4という要素をもつlist型のデータである
  • しかし、同時にsortという機能をも含んでいる
  • なので、x.sort()で機能を使ってデータを小さい順に並び替えられる
  • Pythonでは一般に、オブジェクトがもつ機能はメソッドと呼ばれる

Standard Terminology

  • 1,5,4からなるリストxを作り、それをx.sort()で小さい順に並び替えています。
  • sortは文字列にも有効で、ほかにも順番を逆にするreverseなどもあります。
  • 詳細はこちらを参照してください

Another Example

  • Envelopesというモジュールを使ったOOPの一例です(このモジュール自体を使えるようになる必要はないと思われます)。
  • Envelopesについてはこちらを参照してください
  • Envelope内には送信元のアドレス、送信先のアドレス、件名、本文の4つの要素が含まれています-ここに".add_attachment"を用いてjpg画像ファイルを添付。
  • さらに.sendを使って送信。カッコに入るのはSMTPサーバの名前とそこにログインするための名前/パスワードです。

Why is OOP Useful?

  • OOPは一般的な事象を理解し、整理するのに有用です

ウィンドウ(パソコン上で閉じたり開いたりするアレ)の例を用いた説明

  • ウィンドウはどれもそれらに固有のデータを持っている
  • しかし、それと同時にウィンドウを大きくしたり閉じたりするという機能も持っている
言い換えると
  • 個々のウィンドウは固有のデータとクラスの定義によりオブジェクト/インスタンスとして作られている
  • しかし、メソッドとして実行される一般的な機能はこれらの全てのオブジェクトに共通している

カプセル化

  • OOPを使うということはデータのカプセル化をするということである
  • 変数を構造の中に格納することで、それらの変数が直接アクセスされることを防いでいる
  • こうしないと、グローバル(どこかれでもアクセスできる)名前空間が多数の名前で埋まってしまい、場合によっては競合してしまう
  • あらゆる名前をグローバル名前空間上でアクセス可能にした場合に生じる競合の例
    • OSというモジュールとSYSというモジュールはともにpathというクラスを持っています
    • これを両方ともに"from A import path"という形でインポートしてしまうと、同じグローバル名前空間上の同じ名前を使うことになるため、先に書かれた方のインポートはなかったことになります
  • このような競合を防ぐために
    • "from A import B" は使わずに"import A"で対応し、必要に応じて"A.B"を使いましょう

Defining Your Own Classes

  • データをカプセル化するため、単純なクラスを作成してみましょう
  • 入れたい機能は以下の3つです
    • kを入れるとその0.5乗を返す関数f
    • 0.99で与えられる割引率β(beta)
    • 10で与えられる借入制約κ(kappa)
  • 書いてあるコードでやっていることは以下です
    • Firmというクラスを作成する
    • firmというオブジェクトをFirmのインスタンスにする
    • firmに上述の機能を満たすような属性を与えている
  • たとえば"firm.f(4)"と入力すると2が返ってきます
  • "firm.beta"なら0.99、"firm.kappa"なら10です

Data and Methods

  • 上の例はかろうじてOOPと呼べる程度のものです
  • 通常はクラスを定義したら、オブジェクト内のデータに働きかけるメソッドも定義します
  • 最初はクラスを定義する記述法は複雑に見えますから、シンプルでごく自然なものとしてサイコロを表すところから始めてみましょう
    • データとして保有するのは出ている面の数字だけです
    • メソッドはサイコロを振るという動作だけです

実際にコードを見てみると……

  • "faces"はこのクラス内で共通の(そしてクラス外では無意味な)変数です
    • サイコロを振って出うる目がtupleとして表されています
    • "d=Dice()","e=Dice()"とすると、d.facesとe.facesは(どちらかの中で変更が加えられたとしても)同じものを表示します(今回はtupleなので変更しようがなく、下記のインスタンス変数になったとしても影響がありませんが)
  • "__init__"は特別なメソッドであり、主に初期状態を表します。
    • うまく理解できてないのでここで正確な定義を見てください
    • このメソッドの下で作成されたcurrent_faceの性質は下に記したので、それが参考になるかもしれません
  • "current_face"はインスタンス属性の変数です
    • サイコロを振った後に出ている目を表しています。便宜上、最初は1となっています
    • 同じクラス内でも、d=Dice(),e=Dice()と定義したのちd.rollとe.rollを行った後にd.current_faceとe.current_faceを入力すると返ってくる値が異なります(1/6の確率で同じですが)。上のfacesとの性質の違いに注意しましょう
  • "roll"はメソッドです
    • facesの中の要素をランダムに取り出してその値をcurrent_faceに代入することで「1~6が当確率で出る」という、サイコロを振ったのと同じ状況を作りだしています

Further Details

もうちょっと待ってね

Example 2: The Quadratic Map

もうちょっと待ってね

Special Methods

もうちょっと待ってね

Exercise1

経験累積分布関数のクラスを作成する問題です。

Exercise2

多項式のクラスを作成する問題です。
それにあわせて、xに値を入れるとyを返すメソッドと微分をするメソッドも作成しましょう。
授業は加えて数式を文字で表すメソッドを作りました。
def pri(self):
       strings = ''
       for i,a in enumerate(self.coefficients):
           strings += ' ' + str(a) + ' x^' + str(i) + ' +'
       print strings[:-1]

  • 最終更新:2015-04-27 18:26:28

このWIKIを編集するにはパスワード入力が必要です

認証パスワード