Python class 試験対策 dataclassとか型ヒント

試験対策 classについてもうちょっと深掘りして学ぶ

インスタンスをprintした時に表示される文字列を変更する



class User:
   def __init__(self, name: str):
       self.name = name
       
       
user = User("Taro")
print(user)  

<__main__.User object at 0x101016ed0> と表示される

この表示を変更するためには、__repr__メソッドで変更することができる

class User:
   def __init__(self, name: str):
       self.name = name
       
   def __repr__(self):
       return f"User(name={self.name})"

user = User("Taro")
print(user)

User(name=Taro)

似たようなメソッドに__str__メソッドがある __str__メソッドはprint関数やstr関数でインスタンスを文字列に変換した時に呼び出される __str__メソッドが定義されていない場合は、__repr__メソッドが呼び出される

__str__と__repr__の使い分け方

__str__はユーザーが見るための文字列を返す
__repr__は開発者が見るための文字列を返す

例えば、Userクラスのインスタンスをprintした時には、__str__メソッドが呼び出される 一方、Userクラスのインスタンスをそのまま入力した時には、__repr__メソッドが呼び出される

__len__メソッド

len関数を使ったときに、何の長さを返すかを制御することができる 例えば、虫取り少年のクラスを作成して、そのクラスのインスタンスに対してlen関数を使った時に その虫取り少年が持っているポケモンの数を返すようにする

class MushitoriBoy:
   def __init__(self, pokemons: list):
       self.pokemons = pokemons
       
   def __len__(self):
       return len(self.pokemons)
   

class Pokemon:
   def __init__(self, name: str):
       self.name = name
caterpie = Pokemon("キャタピー")
beedrill = Pokemon("スピアー")
butterfree = Pokemon("バタフリー")
pinsir = Pokemon("カイロス")
pokemons = [caterpie, beedrill, butterfree, pinsir]

mushitori_boy = MushitoriBoy(pokemons)
print("虫取り少年が持っているポケモンの数")
print(len(mushitori_boy))  # 4
虫取り少年が持っているポケモンの数
4

__eq__メソッド

インスタンス同士が等しいかどうかを判定するロジックを自分好みに変更することができる

例えばデジモン同士、ポケモン同士を比較したらTrue デジモンとポケモンを比較したらFalseを返すようにする


class Digimon:
   def __init__(self, name: str):
       self.name = name
       
   def __eq__(self, other):
       if isinstance(other, Digimon):
           return True
       return False

class Pokemon:
   def __init__(self, name: str):
       self.name = name
           
   def __eq__(self, other):
       if isinstance(other, Pokemon):
           return True
       return False
   
digimon = Digimon("ガブモン")
pokemon = Pokemon("ピカチュウ")

print(digimon == digimon)  # True

print(digimon == pokemon)  # False

True
False

データクラスについて

データクラスは、データを保持するためだけのクラス 単純にデータを保持するだけのクラスを作成する際には、データクラスを使うと便利

from dataclasses import dataclass

@dataclass
class User:
   name: str
   age: int

user = User("Taro", 20)
print(user.name)  # Taro

仮にデータクラスを使わない場合

class User:
   def __init__(self, name: str, age: int):
       self.name = name
       self.age = age

と、なってしまうため、データクラスを使うことで、簡潔に書くことができる また読む人にもデータを保持するだけのクラスというのが、わかりやすいコードになる

データの変更ができないデータクラス

@dataclass(frozen=True)
class User:
    name: str
    age: int

このようにfrozen=Trueを指定することで、インスタンスの値を変更することができなくなる

ここで重要なのは例えデータクラスであったとしても、Pythonの型ヒントはあくまでもヒントであるということ つまり、型ヒントをつけていても、実際にその型でない値を代入することができる

@dataclass
class User:
   name: str
   age: int

user = User("Taro", "20")
print(user.age)  # 20

これはPythonの設計思想によるもの。 Pythonは動的型付け言語であり、型ヒントはあくまで開発者へのヒントに過ぎません。実行時に型チェックが行われないため、型ヒントと異なる型の値を代入してもエラーにはなりません。

動的型付け言語であるPythonでは、型チェックが実行時に行われないため、それがメリットでもありデメリットでもあります。

メリット:

柔軟性: 動的型付けにより、変数や関数は任意の型の値や引数を扱うことができます。これにより、コードの記述が簡潔になり、開発速度が向上します。

迅速なプロトタイピング: 型を明示的に定義する必要がないため、アイデアの実装や試作が迅速に行えます。

ダックタイピング: オブジェクトの型ではなく、そのオブジェクトが持つメソッドや属性によって挙動を判断するため、コードの再利用性や拡張性が高まります。

デメリット:

実行時エラーの増加: 型チェックがコンパイル時に行われないため、型に関連するエラーが実行時まで発見されず、バグの原因となることがあります。

可読性と保守性の低下: 型情報がコードに明示されていないと、他の開発者や将来の自分がコードの意図やデータの流れを理解しにくくなります。

ツールサポートの限界: 静的型付け言語に比べ、IDEのコード補完やリファクタリング機能が限定的になる場合があります。

動的型付けによる型チェックの欠如は、開発の柔軟性や迅速性を高める一方で、エラー検出の遅れやコードの可読性低下といったリスクも伴います。プロジェクトの規模や要件に応じて、静的型チェックツールの導入や型ヒントの積極的な活用など、適切な対策を講じることが重要です。

Pythonで型チェックをしてくれるツール

Pythonの型ヒントは、静的型チェックツールを使うことで、実行時エラーを事前に検出することができます。代表的な静的型チェックツールとしては、以下のものがあります。

mypy

mypyは、Pythonの型ヒントに基づいてコードを静的に解析し、型の不整合を検出するツールです。

特徴

Python公式の型チェックツールとして広く使用されています。 Python 3.5以降の型ヒントをサポート。 型の不一致、未定義の変数、属性の誤用などを検出。 インストールと使用方法

pip install mypy

コードをチェックするには:

mypy your_script.py your_script.py:

4: error: Argument 1 to "greet" has incompatible type "int"; expected "str" Found 1 error in 1 file (checked 1 source file)

Pyright

Pyrightは、Microsoftが開発した高速なPython静的型チェッカーです。

特徴

高性能で、大規模プロジェクトでも迅速に型チェックを実行。 VSCode拡張機能としても提供されており、エディタ内でリアルタイムに型エラーを検出。 TypeScriptの技術を活用して開発。 インストールと使用方法

npm install -g pyright

Pyre Pyreは、Meta(旧Facebook)が開発したPythonの静的型チェッカーです。

特徴

インクリメンタルな型チェックが可能で、大規模なコードベースでも高速。 高度な型推論により、明示的な型アノテーションがなくてもある程度のチェックが可能。 カスタム型や高度な型表現をサポート。 インストールと使用方法

pip install pyre-check

初期設定ファイルを生成: pyre init

Pylint

Pylintは、コードの品質チェックとスタイルガイドへの準拠を確認するツールですが、基本的な型チェック機能も備えています。

特徴

PEP 8に準拠したコーディングスタイルのチェック。 未使用の変数や未定義の変数の検出。 限定的な型チェックによる基本的なエラーの発見。 インストールと使用方法

pip install pylint

Typeguard

Typeguardは、実行時に型ヒントを検証するライブラリです。

特徴

実行時に関数の引数や戻り値の型をチェック。 デコレータを使って簡単に適用可能。 動的な型チェックが必要な場合に有用。 インストールと使用方法

pip install typeguard

使用例:

from typeguard import typechecked

@typechecked
def greet(name: str) -> str:
    return "Hello, " + name

greet(123)  # 実行時にTypeErrorが発生
実行結果:

TypeError: type of argument "name" must be str; got int instead

Pytype

Pytypeは、Googleが開発したPythonコードの静的型チェッカーです。

特徴

型推論エンジンにより、型アノテーションがなくても型チェックが可能。 コード補完やリファクタリングの支援。 C拡張モジュールを含む複雑なコードベースでも解析可能。 インストールと使用方法

pip install pytype

静的型チェックツールの活用方法 ツールの選択: プロジェクトの規模やニーズに合わせて適切なツールを選びます。例えば、小規模なプロジェクトではmypy、大規模なプロジェクトではPyreやPytypeが適しています。

CI/CDパイプラインへの統合: 型チェックを継続的インテグレーション(CI)に組み込むことで、コードの品質を維持できます。

エディタやIDEとの連携: 多くの静的型チェックツールは、VSCodeやPyCharmなどのエディタと連携可能です。リアルタイムでエラーを検出でき、生産性が向上します。

チームでの型ヒントの活用: 型ヒントを積極的に使用し、コードベース全体の可読性と保守性を高めます。

まとめ Pythonの動的型付けは開発の柔軟性を高める一方、型に起因するエラーが実行時まで検出されないリスクもあります。静的型チェックツールを活用することで、これらのリスクを軽減し、コードの信頼性を向上させることができます。

プロジェクトの要件や規模に合わせて適切なツールを選び、効率的でバグの少ない開発を目指しましょう。

この記事が気に入ったらサポートをしてみませんか?