0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

WindowsによるPython入門 #10: クラス

Last updated at Posted at 2023-02-24

はじめに

今回はクラスを解説します。

YouTube動画

クラスの定義

クラスは既に解説したように「型」です。
組み込み型のみではなく、自前の型 (クラス) を定義出来ます。
以下の構文でクラスを定義出来ます。

class クラス名:
    変数定義
    メソッド定義    

具体例です。
クラスのメソッドの第一引数には、self を使用します。
変数名は何でも良いのですが、慣例的に self を使用します。

>>> class Dog:  # Dog クラスを定義
...     def __init__(self, cnt):  # コンストラクタを定義
...         self.cnt = cnt
...     def bark(self):
...         print("ワンワン " * self.cnt)
...
>>> d = Dog(2)  # Dog クラスのインスタンスを作成
>>> d.bark()  # メソッドの呼び出し
ワンワン ワンワン 
>> d.cnt  # 属性を参照可能 (変更も可能)
2
>>> d  # デフォルトのクラスの表示内容
<__main__.Dog object at 0x0000029D396B3610>

継承

既存のクラスに機能を追加するには、クラスの「継承」を使用します。
また、同じメソッド名で関数を再定義すると、再定義された方が呼び出されます。
これを「メソッドオーバーライド」と言います。

派生元のクラスを「基底クラス (ベースクラス)」、派生先のクラスを「派生クラス (サブクラス)」と言います。
派生クラスから基底クラスを呼び出すには、super() を使用します。

>>> class Dog:
...     def __init__(self, cnt):
...         self.cnt = cnt
...     def bark(self):
...         print("ワンワン " * self.cnt)
...
>>> class Chihauhau(Dog):
...     def __init__(self, cnt, run_cnt):  # コンストラクタをオーバーライド
...         super().__init__(cnt)  # 基底クラスのコンストラクタを呼び出し
...         self.run_cnt = run_cnt
...     def run(self):  # 新たなメソッドを追加
...         print("ラン " * self.run_cnt)
...     def bark(self):  # メソッドをオーバーライド
...         print("キャンキャン " * self.cnt)
...
>>> c = Chihauhau(2, 3)
>>> c.run()
ラン ラン ラン 
>>> c.bark()  # 派生先のメソッドが呼び出される
キャンキャン キャンキャン 

クラス変数とインスタンス変数

クラスの変数には、クラス変数とインスタンス変数があります。それぞれ以下の通りです。

  • インスタンス変数: インスタンスに属する変数
  • クラス変数: クラスに属する変数
>>> class Animal:
...     word = "ガオー "  # クラス変数
...     def __init__(self, cnt):
...         self.cnt = cnt  # インスタンス変数
...     def cry(self):
...         print(Animal.word * self.cnt)
...
>>> a = Animal(2)
>>> b = Animal(3)
>>> a.cry()
ガオー ガオー
>>> b.cry()
ガオー ガオー ガオー
>>> Animal.word = "ブーブー "  # クラス変数を書き換えると全てのインスタンスに影響が出る
>>> a.cry()
ブーブー ブーブー
>>> b.cry()
ブーブー ブーブー ブーブー

インスタンスメソッドとクラスメソッドと静的メソッド

クラスで定義可能なメソッドには、インスタンスメソッドとクラスメソッドと静的メソッドの 3 通りあります。それぞれ以下の通りです。

  • インスタンスメソッド: インスタンスに属するメソッド (通常のメソッド)
  • クラスメソッド: クラスに属するメソッド
  • 静的メソッド: インスタンスにもクラスにも属さないメソッド (関数のようなもの)

クラスメソッドと静的メソッドは、インスタンスがなくても呼び出す事が出来ます。
また、クラスメソッドと静的メソッドは、クラスを継承した時に違いが出ます。
クラスメソッドは、継承先のクラスを参照出来ますが、静的メソッドは参照出来ません。

>>> class Animal:
...     word = "ガオー "
...     @classmethod
...     def cry(cls):
...         print(cls.word * 2)
...     @staticmethod
...     def cry_static():
...         print(Animal.word * 2)
...
>>> class Sheep(Animal):
...     word = "メェ "
...
>>> class Duck(Animal):
...     word = "ガーガー "
...
>>> Sheep.cry()  # Sheep クラスの word が参照される
メェ メェ
>>> Sheep.cry_static()
ガオー ガオー
>>> Duck.cry()  # Duck クラスの word が参照される
ガーガー ガーガー
>>> Duck.cry_static()
ガオー ガオー

特殊メソッド

掛け算を表す演算子の「*」を適用した時に、int 型のオブジェクトと str 型のオブジェクトで挙動が異なりました。
これは、演算子の挙動を表す特別なメソッドが実装されているからです。
これを「特殊メソッド」もしくは、「マジックメソッド」と言います。
*」の場合、__mul__という特殊メソッドが実装されています。
このメソッドを再定義 (オーバーロード) する事で、挙動を変更する事が出来ます。

>>> class MyStr(str):
...     def __mul__(self, cnt):  # 演算子「*」をオーバーロード
...         return "[" * cnt + self.__str__() + "]" * cnt
...
>>> a ="abc"
>>> a * 3
'abcabcabc'
>>> b = MyStr("abc")
>>> b * 3  # MyStr の __mul__ が呼ばれる
'[[[abc]]]'

特殊メソッドは、他にも色々ありますが、ここでは省略します。

_str_と_repr_

例えば、bytes 型のように内部データとしては、「0 から 255 までの整数値の配列」なのに対して、print() 関数などで表示されるのは、「バイト列の文字列」です。
このように、「データ」と「表示」は異なる概念です。
クラスのオブジェクトの表示内容を実装する特殊メソッドが、__str____repr__ です。

__str____repr__ の違いは以下の通りです。

  • __str__: ユーザが読みやすい文字列
  • __repr__: eval() 関数などで元に戻せる文字列

__str__ 呼び出しが必要な場面で、__str__ が実装されていない場合は、__repr__ が呼び出されます。
(逆に、__repr__ 呼び出しが必要な場面で、__repr__ が実装されておらず、__str__ が実装されていても、__str__ は呼び出されず、デフォルトの文字列が取得されます)

>>> class BracketStr(str):
...     def __str__(self):
...         return "[" + super().__str__() + "]"
...
>>> s = BracketStr("abc")
>>> print(s)  # __str__が呼ばれる
[abc]
>>> s.__str__()
'[abc]'
>>> s  # __repr__が呼ばれる
'abc'
>>> s.__repr__()
"'abc'"
>>> eval(_)
'abc'

データクラス

クラスにメソッドは不要でデータのみ必要な場合に、Python 3.7 からデータクラスというものが用意されました。
以下の例のように使用します。

>>> from dataclasses import dataclass
>>>
>>> @dataclass
... class Person:
...     name: str
...     age: int
...     gender: str = "Male"  # デフォルト値を指定可能
...
>>> p = Person("PythonMan", 100)
>>> p
Person(name='PythonMan', age=100, gender='Male')
>>> p.name, p.age, p.gender
('PythonMan', 100, 'Male')
>>> p.__str__()
"Person(name='PythonMan', age=100, gender='Male')"
>>> p.__repr__()
"Person(name='PythonMan', age=100, gender='Male')"

他にも色々機能はありますので、他は公式ドキュメントをご参照下さい。

dataclasses --- データクラス

おわりに

以上、クラスに関して解説しました。
次回は、モジュールに関して解説します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?