プロジェクト

全般

プロフィール

操作

第4章 Python のクラス

Python 実践レシピ (技術評論社)

4.1 class 構文

  • class 定義
class クラス名:
    属性 = 

    def メソッド名(self, ...):
        メソッド処理

例:Userクラス (class_sample.py)

class User:
    type = None

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

    def increment_age(self):
        self.age += 1
    
    def start_name(self):
        if len(self.name) > 0:
            return self.name[0]
        else:
            return ""
  • インスタンス化
from class_sample import User

user1 = User("smith", 41, "Shizuoka")
user2 = User("tatsuya", 20, "Nagoya")
  • (インスタンス)メソッド定義で第1仮引数とする self は、インスタンスが渡される
    • メソッドの実引数 1, 2, ... 番目は、仮引数 2, 3, ... 番目に対応する
    • メソッド定義時の self は別の名前でも良いが、慣例としてこの名前

4.2 属性とメソッド

  • __init__() コンストラクターメソッド
  • データ属性
    • クラス変数 (全インスタンスで共有される) User.type User.type = "SE"
    • インスタンス変数 (クラス定義内で self.変数名 で使用) user2.name user2.age = 30
    • 注意:追加調査と実験で確かめた
      • 同名のクラス変数とインスタンス変数が存在すると、インスタンス変数参照が優先される
        • クラス変数へのアクセスメソッドなどで対応できる
      • クラス変数への代入のつもりで、インスタンスを使用して代入すると、新たに同名のインスタンス変数が生成されてしまう (その後はインスタンスオブジェクトからは直接クラス変数参照はできない)
        >>> from class_sample import User
        >>>
        >>> user = User("smith", 41, "Shizuoka")
        >>> User.type = "SE"  # クラス変数へ代入
        >>> User.type  # クラス変数が参照されている
        'SE'
        >>> user.type  # クラス変数が参照されている
        'SE'
        >>> user.type = "NEET"  # ここで user のインスタンス変数 type が新規定義されて値代入される
        >>> User.type  # クラスからはクラス変数が参照されている
        'SE'
        >>> user.type  # 新規定義されたインスタンス変数を参照してしまう
        'NEET'
        >>>
        
      
      
  • メソッド
    • インスタンスメソッド
      • 暗黙的に第1引数へ インスタンスオブジェクト を渡して実行される
    • クラスメソッド
      • @classmethod デコレーターをメソッドに使って定義する
      • 暗黙的に第1引数へ クラスオブジェクト を渡して実行される
    • 静的メソッド
      • @staticmethod デコレーターをメソッドに使って定義する
      • 暗黙的に渡されるオブジェクトは無い
  • 特殊メソッド
    • 組み込み関数、演算子(==, + 等)利用時の動作等の定義
    • 以下、主な特殊メソッド
特殊メソッド 概要
__init__() コンストラクターメソッド
__repr__() オブジェクトを print() 関数で出力した時の文字列表現を定義
__len__() オブジェクトを len() 関数へ渡した際の値を定義
__call__() 呼び出し可能化
__str__() 文字列型への変換
__eq__() 演算子 ==
__lt__() 演算子 <
__le__() 演算子 <=
__ne__() 演算子 !=
__gt__() 演算子 >
__ge__() 演算子 >=
__add__() 演算子 +
__sub__() 演算子 -
__mul__() 演算子 *
__truediv__() 演算子 /
  • インスタンスメソッドのプロパティ化
    • @property デコレーターを使用すると、括弧無しで計算(処理)結果を取得できる
  • クラスメソッド使用例
    • コンストラクタへの引数に依らないインスタンスを生成する

4.3 継承

  • 継承構文
    • クラス定義の際に、クラス名に続けて括弧内に親クラス名を記述
    class 子クラス名(親クラス名):
        pass
    
  • unittest.TestCase を継承する例
import unittest

class TestSample(unittest.TestCase):
    def setUp(self):
        self.target = "foo"

    def test_upper(self):
        self.assertEqual(self.target.upper(), "FOO")
  • 多重継承
    • Python では多重継承サポート
    • 以下の様に記載し、この場合は Child インスタンスの属性・メソッド参照では、Child → Parent1 → Parent2 の順に定義を探して、最初に見つかったものが対象となる
    • 多重継承の継承順位を MRO (Method Resolution Order) という仕組みで検索する
    class Child(Parent1, Parent2):
        pass
    
  • フレームワークでは継承使用を前提としたクラスが多く使われる

4.4 dataclass

  • dataclasses.dataclass はクラスデコレーター
    • データ組み合わせとしての型を簡単に定義
    • __init__() __repr__() を定義しなくてもよい
    • 引数 frozen=True により、イミュータブルとなり値変更できない型として定義できる
    • デフォルト値を指定した属性を指定すると、インスタンス化でのコンストラクタ実引数が可変化できる
    # dataclass.py
    from dataclasses import dataclass
    
    @dataclass
    class User:
        name: str
        age: int
        address: str
    
    @dataclass(frozen=True)
    class FrozenUser:
        name: str
        age: int
        address: str
    
    @dataclass
    class User:
        name: str
        age: int
        address: str
        active: bool = False  # コンストラクタ引数は3 or 4個
    
    • dataclasses モジュールの asdict() astuple() によって、dataclass のインスタンスを変換できる
      • asdict() 属性名の文字列がキーとなる辞書
      • astuple() 属性値のみのタプル
  • dataclass の属性値の型ヒントは「ヒント」なので、使用時には自由な型を指定できてしまう事に注意

4.5 オブジェクト関連関数

関数名 解説 返り値
id(object) 識別値 int
type(object) 型オブジェクト取得 type
isinstance(object, classinfo) object が classinfo (または classinfo の継承先クラス) のインスタンスであるか判定 bool
issubclass(class, classinfo) class が classinfo のインスタンスであるか判定 bool
help(object) object のヘルプを表示 None
dir(object) object が持つ属性・メソッドのリストを返す list
  • isinstance()
    • 第2引数に型のタプルを渡す使用法がある
      • タプルのどれかのインスタンスであれば True
      >>> isinstance(True, bool)
      True
      >>> isinstance(True, int)  # bool は int を継承している
      True
      >>> isinstance(True, str)
      False
      >>> isinstance(True, (int, str))
      True
      >>>
      
    • フレームワークの作成時によく使用される
      • フレームワークに含まれる class の継承を想定する場合など
  • dir()
    • すべての属性・メソッドが取得されるので、デバッグ時等に使用
    >>> dir("test")
    ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
    
  • 上記のオブジェクト関連関数は組み込み関数なので、インポート不要
    • これらの関数と同名の変数等を使用すると混乱を生じるので避ける
      • (例) def func(type): ※仮引数に type を使用

Tatsuya ISHIGAKI さんが6ヶ月前に更新 · 1件の履歴