第9章 クラス(40問中2問)
Python3基礎試験のクラス:クラス変数・継承・isinstanceの結果
第9章のクラスは、どの値がインスタンスごとに別で、どの値が共有されるかを読み取る問題が中心です。このページでは、クラス変数とインスタンス変数、リストをクラス変数に置いたときの共有、継承とオーバーライド、isinstance()とissubclass()、先頭のアンダースコアの扱いを、Python 3.9.6で実際に実行した結果で確かめます。覚えるのは3つです。クラス変数は全インスタンスで共有、派生クラスは基底クラスを上書きできる、isinstance() は派生クラスのインスタンスも True にします。
このページは試験の学習用の整理です。公式の問題は転載せず、コードはすべて説明用に作った例です。表の d と e は、最初のコードで作ったDogのインスタンスです。
この記事の目次
公式情報の確認
試験日、料金、申込条件、試験方式など変動する情報は、公式情報を最終確認してください。 当サイトの一次情報確認日: 2026-09-18。
試験の出題範囲・実施要項は変動するため、受験前に公式情報を確認してください。
結論
- クラス変数はすべてのインスタンスで共有され、インスタンス変数はインスタンスごとに別。インスタンスに同名を代入すると、そのインスタンスだけ別の値になる
- リストのように変更できるオブジェクトをクラス変数に置くと、全インスタンスで共有される。インスタンスごとに別にしたいときは __init__() の中で作る
- 派生クラスは基底クラスのメソッドを上書きでき、派生クラスに無い属性は基底クラスから探される
- isinstance() は派生クラスのインスタンスも基底クラスとして True にし、issubclass() はクラスの継承関係を見る。先頭に2つのアンダースコアを付けた名前は _クラス名__名前 に置き換えられる
クラス変数とインスタンス変数
公式チュートリアルによると、インスタンス変数はそれぞれのインスタンスについて固有のデータのためのもので、クラス変数はそのクラスのすべてのインスタンスによって共有される属性やメソッドのためのものです。次の表は、最初に下のコードでインスタンスを2つ作った状態から、上の行から順に実行した結果です。
class Dog:
kind = 'canine'
def __init__(self, name):
self.name = name
d = Dog('Fido')
e = Dog('Buddy')| コード | 実行結果 | ひとこと |
|---|---|---|
d.kind, e.kind | ('canine', 'canine') | クラス変数は、どのインスタンスからも同じ値が見える |
d.name, e.name | ('Fido', 'Buddy') | __init__() で self.name に入れた値は、インスタンスごとに別 |
d.kind = 'wolf'
d.kind, e.kind, Dog.kind | ('wolf', 'canine', 'canine') | インスタンスに同名を代入すると、そのインスタンスだけ別の値になる。クラス変数は変わらない |
Dog.kind = 'pet'
d.kind, e.kind | ('wolf', 'pet') | クラスに代入すると、自前の値を持たないインスタンスにだけ反映される |
d.kind に代入すると、クラス変数ではなく d だけの変数が新しくできます。そのため、3行目の結果で Dog.kind は canine のままです。そのあと Dog.kind を pet に変えると、自分の値を持たない e には反映され、wolf を持つ d には反映されません。
リストをクラス変数に置くと共有される
公式チュートリアルは、変更できるオブジェクト(リストや辞書)をクラス変数にすると、思わぬ結果になりうると説明しています。公式の例は、Dog に芸(tricks)を覚えさせるものです。tricks のリストをクラス変数にすると、1つのリストをすべての Dog が共有します。
次の表の2つの行は、それぞれ新しく Dog を定義し、インスタンスも作り直しています。
| コード | 実行結果 | ひとこと |
|---|---|---|
class Dog:
tricks = []
def add_trick(self, trick):
self.tricks.append(trick)
d = Dog()
e = Dog()
d.add_trick('roll over')
e.add_trick('play dead')
d.tricks, e.tricks | (['roll over', 'play dead'],['roll over', 'play dead']) | リストはクラス変数なので共有され、どちらにも2つ入る |
class Dog:
def __init__(self, name):
self.tricks = []
def add_trick(self, trick):
self.tricks.append(trick)
d = Dog('Fido')
e = Dog('Buddy')
d.add_trick('roll over')
e.add_trick('play dead')
d.tricks, e.tricks | (['roll over'],['play dead']) | __init__() で作ればインスタンスごとに別のリストになる |
append() はリスト自体を変更するので、共有されたリストには全員ぶんが入ります。インスタンスごとに別のリストにしたいときは、__init__() の中で self.tricks = [] と作ります。
継承とオーバーライド
公式チュートリアルによると、派生クラスは基底クラスのメソッドを上書き(override)することができます。要求された属性がクラスに見つからなかった場合は、基底クラスに検索が進みます。
| コード | 実行結果 | ひとこと |
|---|---|---|
class Animal:
def speak(self):
return '...'
def kind(self):
return 'animal'
class Cat(Animal):
def speak(self):
return 'Meow'
c = Cat()
c.speak() | 'Meow' | 派生クラスで同じ名前のメソッドを定義すると、基底クラスのものを上書きする |
c.kind() | 'animal' | 派生クラスに無ければ、基底クラスを探して見つかる |
Cat.speak() | TypeError: speak() missing 1 required positional argument: 'self' | クラスの名前から直接呼ぶと、self に当たる引数を自分で渡す必要がある。Cat.speak(c) なら動く |
同じ名前なら派生クラス、無ければ基底クラスの順に探されます。Cat は speak() だけを上書きしているので、kind() は Animal のものが使われます。最後の行は、クラスの名前から直接メソッドを呼ぶと self を渡す必要があることを示す例です。
isinstance()とissubclass()
公式チュートリアルによると、isinstance(obj, int) は obj.__class__ が int か int の派生クラスの場合に限り True になります。issubclass() はクラスの継承関係を調べ、bool は int のサブクラスなので issubclass(bool, int) は True、float は int のサブクラスではないので issubclass(float, int) は False です。
| コード(Animal・Cat は上の例のクラス) | 実行結果 | ひとこと |
|---|---|---|
isinstance(c, Cat), isinstance(c, Animal) | (True, True) | 派生クラスのインスタンスは、基底クラスのインスタンスでもある |
isinstance(Animal(), Cat) | False | 基底クラスのインスタンスは、派生クラスのインスタンスではない |
issubclass(Cat, Animal), issubclass(Animal, Cat) | (True, False) | issubclass() はクラスどうしの継承関係を見る。向きがある |
issubclass(bool, int), isinstance(True, int) | (True, True) | bool は int のサブクラスなので、True は int のインスタンスでもある |
isinstance() の第1引数はインスタンス、issubclass() の第1引数はクラスです。どちらも、派生クラスから基底クラスの向きでだけ True になります。
先頭のアンダースコア
公式チュートリアルによると、Python には、オブジェクトの中からしかアクセスできないプライベートなインスタンス変数はありません。ほとんどの Python コードが従う慣習として、アンダースコアで始まる名前(_spam など)は非公開の API として扱います。また、__spam のように先頭に2個以上、末尾に1個以下のアンダースコアを持つ識別子は、_classname__spam に置き換えられます。この仕組みは名前マングリングと呼ばれます。
| コード | 実行結果 | ひとこと |
|---|---|---|
class Box:
def __init__(self):
self._a = 1
self.__b = 2
bx = Box()
bx._a | 1 | 先頭が 1 つのアンダースコアは、非公開とみなす慣習。実際には読める |
bx.__b | AttributeError: 'Box' object has no attribute '__b' | 先頭が 2 つのアンダースコアの名前は、そのままでは見つからない |
bx._Box__b | 2 | _クラス名__名前 に置き換えられているため、この名前なら読める |
アンダースコア1つは慣習だけで、アンダースコア2つは名前が置き換わります。どちらも、アクセスを完全に禁止する仕組みではありません。
Python3エンジニア認定基礎試験の学習に使う書籍(Amazon)
試験範囲を通して読むときの1冊です。読んだ章は、このサイトの章別問題で確かめられます。
よくある質問
クラス変数とインスタンス変数は、何が違いますか?
公式チュートリアルによると、インスタンス変数はそれぞれのインスタンスに固有のデータのためのもので、クラス変数はそのクラスのすべてのインスタンスによって共有される属性やメソッドのためのものです。リストのような変更できるオブジェクトをクラス変数に置くと、すべてのインスタンスで共有されます。
isinstance() と issubclass() は、何を調べますか?
公式チュートリアルによると、isinstance() はインスタンスの型を調べ、isinstance(obj, int) は obj.__class__ が int か int の派生クラスの場合に限り True になります。issubclass() はクラスの継承関係を調べ、bool は int のサブクラスなので issubclass(bool, int) は True です。
アンダースコアで始まる名前は、外から使えませんか?
公式チュートリアルによると、Python には外から触れない「プライベート」なインスタンス変数はありません。ただし、_spam のようにアンダースコアで始まる名前は非公開の API として扱う慣習があります。__spam のように先頭に2個以上のアンダースコアを持つ名前は、_classname__spam に置き換えられます。
第9章のクラスは、何問出ますか?
このサイトが整理した公式の章別出題数では、40問中2問(5.0%)です。出題数は少ないため、クラス変数とインスタンス変数、継承、isinstance()、名前の置き換えの要点に絞って確認するのが効率的です。
