Python × 入門 | #16 クラスを使ってみよう

0-15では return とスコープを学びました。今回のテーマ「クラス」は、それをもう一段進めた考え方です。用語が多く、最初は面食らうかもしれません。まず言葉の意味を整理してから、ブロックを順に確認しましょう。

Python × 入門 | #16 クラスを使ってみよう

まずはPycoBlocksを開こう

下のPycoBlocksで直接作業するか、別タブで開き、生成されるPythonコードを見ながら進めてください。

まず用語を整理しよう

クラスには専門用語が6つ出てきます。今は「なんとなくそういうものか」程度でかまいません。ブロックを動かすうちに、自然とわかってきます。

用語 読み方 一言で言うと
クラス クラス データと処理をまとめた「設計図」
インスタンス インスタンス 設計図から作った「実体」
属性 ぞくせい インスタンスが持つデータ(self.〇〇 で書く)
メソッド メソッド クラスの中に定義する「関数」のこと
self セルフ 「自分自身のインスタンス」を指す特別な変数
__init__ ダンダーイニット インスタンスを作るとき自動で呼ばれる特別なメソッド

これらの用語を、「犬のキャラクター」にたとえながら説明します。

クラス = 犬の「設計図」

「名前を持ち、あいさつができる犬」の設計図を考えてください。この設計図そのものがクラスです。設計図は1枚でも、そこから何匹でも犬を作れます。

インスタンス = 設計図から作った「本物の犬」

設計図をもとに実際に作った犬(「ポチ」「バディ」など)がインスタンスです。同じ設計図から作っても、それぞれ別々の名前を持つ独立した個体です。

属性 = その犬が持つ「データ」

「名前」や「年齢」など、その犬それぞれが持つデータが属性です。Pythonでは self.nameself.age のように self. を付けて書きます。属性はメソッドをまたいでずっと保存され続けます。

メソッド = その犬が「できること」

「あいさつをする」「走る」など、その犬ができる行動がメソッドです。関数とよく似ていますが、クラスの中に定義し、第1引数に必ず self を書く点が異なります。dog.greet() のように「インスタンス名.メソッド名()」の形で呼び出します。

self = 「自分自身」を指す変数

犬が「ぼくの名前はポチです」と言うとき、「ぼく」にあたるのが self です。メソッドの中で self.name と書くと、そのメソッドを呼び出した犬自身の名前を参照できます。どのインスタンスから呼ばれても、self はその呼び出し元を自動的に指します。

__init__ = 犬を作るときの「初期設定」

Dog("ポチ") と書いてインスタンスを作る瞬間に、自動で呼ばれる特別なメソッドです。「作るときに名前を渡して、その犬の属性として保存する」という初期設定を担います。名前の前後にアンダーバーが2つずつ(__init__)あるのが特徴で、この形は変えられません。

用語のイメージがつかめたら、実際のブロックを確認していきます。

ステップ1:Dogクラスのブロックをひとつひとつ読んでみよう

まず完成したブロック全体を確認してください。

intro_0-16_a_dog_intro

ブロックは大きく2つに分かれています。上の紫のまとまりがクラスの定義(設計図を作る部分)で、下の緑〜紫の2行が実際にインスタンスを作って使う部分です。それぞれのブロックを見ていきます。

① クラスの入れ物

intro_0-16_s1_class_def

「クラス Dog を定義する」ブロックがクラス全体の入れ物です。Dog という名前の設計図をここで宣言し、このくぼみの中に __init__ やメソッドをまとめて入れます。

class Dog:

② __init__ で初期設定する

intro_0-16_s1_init

「初期化(self, 引数: name ▼)」ブロックが __init__ メソッドです。Dog("ポチ") と書いてインスタンスを作る瞬間に自動で呼ばれ、引数 name(プルダウンで選ぶ変数)には渡した "ポチ" が入ります。

中の「self.name に name ▼ を入れる」ブロックが、受け取った name属性として保存する処理です。self.name に入れることで、後から greet() を呼んだときにも自分の名前を参照できます。

    def __init__(self, name):
        self.name = name

③ 属性の読み書き(self.〇〇)

intro_0-16_s1_self_set

self.nameself は「この犬自身」を指します。self.name は「この犬が持つ名前」のことです。self. から始まる変数が属性で、ポチなら "ポチ"、バディなら "バディ" とインスタンスごとに別々の値を持ちます。

④ メソッドで「できること」を定義する

intro_0-16_s1_greet

「メソッド greet(引数なし)」ブロックが、犬の「あいさつをする」メソッドです。self.name を参照しているので、どのインスタンスから呼ばれても、その犬自身の名前が表示されます。

    def greet(self):
        print("こんにちは!ぼくの名前はね、" + self.name + "!")

⑤ インスタンスを作って、メソッドを呼ぶ

intro_0-16_s1_instance

「変数 dog ▼ を クラス Dog(引数: "ポチ")で作る にする」ブロックで、設計図からインスタンスを作ります。Dog("ポチ") と書いた瞬間、次の4つが順番に実行されます。

  1. __init__ が自動で呼ばれる
  2. 引数 name"ポチ" が入る
  3. self.name = "ポチ" が実行され、このインスタンスの属性として保存される
  4. できあがったインスタンスが変数 dog に代入される

続く「dog ▼ . greet(引数: )を呼ぶ」ブロックで、dog のメソッド greet を実行します。このとき self は自動で dog を指すので、self.name"ポチ" になります。

ブロック全体が生成するコードと実行結果です。

class Dog:
    def __init__(self, name):
        self.name = name
    def greet(self):
        print("こんにちは!ぼくの名前はね、" + self.name + "!")

dog = Dog("ポチ")
dog.greet()
こんにちは!ぼくの名前はね、ポチ!

ステップ2:メソッドで属性を変えてみよう

メソッドは属性を読むだけでなく、書き換えることもできます。Counter(カウンター)クラスで試してみましょう。

intro_0-16_b_counter_tick

__init__ で受け取った startself.value として保存しています。tick() メソッドは呼ばれるたびに self.value を1ずつ増やす処理です。

ここで押さえておきたいのは、属性の変化はインスタンスに引き継がれる点です。tick() を呼んで増えた値が self.value に上書きされるので、次に tick() を呼んだときはその値からさらに1増えます。普通の変数と違い、属性はメソッドをまたいで持続します。

class Counter:
    def __init__(self, start):
        self.value = start
    def tick(self):
        self.value = self.value + 1

counter = Counter(0)
counter.tick()
counter.tick()
print(counter.value)
2

ステップ3:インスタンスはそれぞれ独立している

同じクラスから複数のインスタンスを作ると、それぞれが独立した属性を持ちます。設計図は1枚でも、そこから作ったインスタンスはお互いに干渉しません。

intro_0-16_c_two_counters
class Counter:
    def __init__(self, start):
        self.value = start
    def tick(self):
        self.value = self.value + 1

a = Counter(0)
b = Counter(100)
a.tick()
b.tick()
print(a.value)
print(b.value)

a.tick() を呼んでも、変わるのは a.value だけです。b.value は100のままです。ポチが何かをしてもバディには関係ない——インスタンスはそれと同じです。

1
101

コーディングモードで書いてみよう

慣れてきたら、属性を複数持たせたり、return で計算結果を返すメソッドを作ったりできます。Rectangle(長方形)クラスで面積を求める例です。

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    def area(self):
        return self.width * self.height

r = Rectangle(4, 3)
print(r.area())

__init__ で2つの属性(self.widthself.height)を保存しているので、area() メソッドはその2つを掛け合わせるだけで面積 12 を返せます。

演習課題

課題16-1:別の名前で犬を作ろう

ステップ1の Dog クラスを使って、"バディ" という名前の犬を変数 buddy に作り、greet() を呼んでください。

詰まったときはこの順で考えてみてください。

  1. クラスの定義(設計図)は変える必要があるか?
    → 名前が違うだけで、設計図の構造は変わりません。Dog クラスの定義はそのまま使えます。
  2. インスタンスを作るブロックを選ぶ
    →「変数 buddy ▼ を クラス Dog(引数: "バディ")で作る にする」ブロックを使います。引数に渡す文字列を "バディ" にしてください。
  3. メソッドを呼ぶブロックを選ぶ
    →「buddy ▼ . greet(引数: )を呼ぶ」ブロックで呼び出します。インスタンスのプルダウンを buddy に変えましょう。
▶ 模範解答と解説を見る

ブロックの組み合わせ例:

intro_0-16_ans1_intro_dog
class Dog:
    def __init__(self, name):
        self.name = name
    def greet(self):
        print("こんにちは!ぼくの名前はね、" + self.name + "!")

buddy = Dog("バディ")
buddy.greet()

解説: 変わったのは最後の2行だけです。Dog("バディ") と書くことで __init__name"バディ" が入り、self.name に保存されます。buddy.greet() を呼んだとき selfbuddy を指すので、self.name"バディ" になります。同じクラス(設計図)から、何匹でも違う名前の犬インスタンスが作れます。

課題16-2:add3()メソッドを追加しよう

ステップ2の Counter クラスに、self.value を3増やすメソッド add3() を追加してください。Counter(10) でインスタンスを作り、add3() を呼んだ結果を表示してください。

詰まったときはこの順で考えてみてください。

  1. tick() メソッドの中身を確認する
    →「self.value に self.value + 1 を入れる」です。属性を1増やして自分自身に上書きしています。
  2. add3() メソッドを tick() と同じ構造で追加する
    →「メソッド add3(引数なし)」ブロックを tick ブロックの次につなぎます。中身は「self.value に self.value + 3 を入れる」にします。
  3. インスタンスを作る
    →「変数 c ▼ を クラス Counter(引数: 10)で作る にする」ブロックで、初期値10のカウンターを作ります。
  4. メソッドを呼んで確認する
    →「c ▼ . add3(引数: )を呼ぶ」の後に c.value を表示します。10+3=13 が出れば成功です。
▶ 模範解答と解説を見る

ブロックの組み合わせ例:

intro_0-16_ans2_counter_plus3
class Counter:
    def __init__(self, start):
        self.value = start
    def tick(self):
        self.value = self.value + 1
    def add3(self):
        self.value = self.value + 3

c = Counter(10)
c.add3()
print(c.value)

解説: add3()tick() と同じ構造で、足す数を1から3に変えただけです。1つのクラスにメソッドはいくつでも追加でき、どのメソッドも属性 self.value を読み書きできます。Counter(10) で初期値10にして add3() を1回呼ぶと、self.value13 になります。

まとめ

  • クラスはデータ(属性)と処理(メソッド)をひとまとめにした「設計図」です
  • インスタンスは設計図から作った実体です。クラスは1つでも、インスタンスは何個でも作れます
  • 属性self.〇〇)はインスタンスごとに独立したデータです。メソッドをまたいで保存され続けます
  • メソッドはクラスの中に定義する関数です。第1引数に必ず self を書き、インスタンス名.メソッド名() で呼び出します
  • self は「そのメソッドを呼び出したインスタンス自身」を指します
  • __init__ はインスタンスを作るときに自動で呼ばれ、属性の初期値を設定する特別なメソッドです

次は、プログラムが予期しないエラーを起こしたとき、クラッシュさせずに対応する「例外処理」を学びます。→ Python × 入門 | #17 エラーをつかまえよう

PAGE TOP