ユーニックス総合研究所

  • home
  • archives
  • python-kata-kakunin

Pythonで型確認を行う方法と実践的テクニック【type関数, isinstance関数】

  • 作成日: 2023-06-16
  • 更新日: 2023-12-25
  • カテゴリ: Python

Pythonで型確認を行う

Pythonは動的型付けの言語で型が内蔵されています。
この型を確認するにはtype関数やisinstance関数を使います。

この記事ではPythonの型確認の方法を解説していきます。

関連記事
Djangoでオブジェクトを一括作成・更新【bulk_create, bulk_update】
DjangoのModel.objects.filter()の使い方【QuerySet】
Djangoのmodelのcreate()の使い方【Python】
Django入門: ルートの設定 ~ 簡単な一行掲示板アプリを作る その4【Windows10】
NumPyのappend()の使い方: 配列の末尾に要素を追加
Numpyのarangeの使い方: 指定範囲の数列を生成する
Python3でYoutube Data APIを使ってキーワード検索する
PythonからC言語(my.puts)を呼び出して実行する

type関数

type関数は変数の型を取得するときに使われます。

print(type(1))  
# <class 'int'>  

print(type(1.2))  
# <class 'float'>  

print(type(True))  
# <class 'bool'>  

print(type([]))  
# <class 'list'>  

print(type({}))  
# <class 'dict'>  

type()で取得したオブジェクトはtype型のオブジェクトです。

t = type(1)  
print(type(t))  
# <class 'type'>  

type関数で型の判定

type関数の返す型を使って型判定することが可能です。
is演算子と合わせて使います。

print(type(1) is int)  
# True  

print(type(True) is dict)  
# False  

自作関数などを作ってわかりやすくする方法もあります。
たとえばis_int()関数の定義です。

def is_int(v):  
    return type(v) is int  


print(is_int(1))  
# True  

複数の型と判定を取りたい場合はin演算子と併用します。

print(type(1) in [int, bool])  
# True  

print(type(True) in [int, bool])  
# True  

print(type([]) in [int, bool])  
# False  

これを使うと例えばis_int_or_bool()関数みたいな定義もできます。

def is_int_or_bool(v):  
    return type(v) in [int, bool]  


print(is_int_or_bool(1))  
# True  

print(is_int_or_bool(True))  
# True  

print(is_int_or_bool([]))  
# False  

取得した型から値を生成

type関数で取得した型から値を生成することも出来ます。

t = type(1)  

print(t())  
# 0  

print(t(100))  
# 100  

これはたとえば自作クラスなどにも応用できます。
クラスの宣言が無くても値から型を取得すればその型のオブジェクトを作れるということです。

class Animal:  
    def __init__(self):  
        self.age = 20  


an = Animal()  
t = type(an)  
print(t())  
# <__main__.Animal object at 0x000001C9D59E70D0>  

isinstance関数

isinstance関数は2つの引数を取ります。
1つ目に判定したいオブジェクト、2つ目に判定したい型を指定します。
オブジェクトが指定した型であればTrueを返し、違っていればFalseを返します。

print(isinstance(1, int))  
# True  

print(isinstance(True, bool))  
# True  

複数の型と判定する

isinstance関数の第2引数には複数の型を指定できます。
その場合はいずれかの型とマッチしていたらTrueを返します。

print(isinstance(1, (int, bool)))  
# True  

print(isinstance(True, (int, bool)))  
# True  

print(isinstance([], (int, bool)))  
# False  

スーパークラスへのマッチ

またisinstance関数はスーパークラスともマッチします。
たとえばboolintのサブクラスなので以下のコードのような結果になります。
issubclass()は第1引数が第2引数のサブクラスかどうか判定する関数です)

print(isinstance(True, int))  
# True  

# boolはintのサブクラス  
print(issubclass(bool, int))  
# True  

型確認を使った実践的テクニック

Pythonの型確認を使った実践的なテクニックを紹介します。

  • 防御的プログラミング
  • プロパティにおける型チェック
  • typeによる依存関係の解消

防御的プログラミング

防御的プログラミングとは外部からの入力を念入りにチェックしてエラーなどを発生させる処理を言います。

Pythonでは動的型付けが採用されていますので関数の引数には型判定がありません。
ですので関数内で引数の型をチェックし、許容できない型の場合はエラーを発生させる、というのが防御的な手法になります。
たとえば以下のようにです。

def mul3(n: int):  
    if not isinstance(n, int):  
        raise TypeError('invalid type')  
    return n * 3  


print(mul3(2))  
# 6  

print(mul3(True))  
# 3  

try:  
    print(mul3([]))  
except TypeError as e:  
    print(e)  
    # invalid type  

防御的プログラミングは開発コストが上がる特性がありますが、型チェックを行うためその分プログラムが堅牢になるというメリットがあります。
セキュアな処理が必要なプログラムなどでは導入してみる価値はあるかと思います。

プロパティにおける型チェック

クラスにはプロパティが定義できます。
プロパティを定義するとオブジェクトの属性への代入を監視できます。
この監視のさいにセッターに型チェックを入れておくとプログラムが堅牢になります。

class Animal:  
    def __init__(self):  
        self._age = 20  

    @property  
    def age(self):  
        return self._age  

    @age.setter  
    def age(self, age: int):  
        if type(age) is not int:  
            raise TypeError('invalid type')  
        self._age = age  


an = Animal()  

an.age = 30  
print(an.age)  
# 30  

try:  
    an.age = []  
except TypeError as e:  
    print(e)  
    # invalid type  

仮にセッターでageにリストなどを指定しても型チェックでエラーになるのでバグが早期発見可能になります。

typeによる依存関係の解消

例えば以下のようなプロジェクトを考えます。

# animal.py  
class Animal:  
    def __init__(self):  
        self._age = 20  
# sub.py  
def hello(animal):  
    Animal = type(animal)  

    an = Animal()  
    print(an)  
    # <animal.Animal object at 0x000001EFF731B910>  
# main.py  
import animal  
import sub  

an = animal.Animal()  
sub.hello(an)  

sub.pyではAnimalを参照してますがimport等は使っていません。
しかしAnimalクラスからオブジェクトは生成できています。
これはmain.pyAnimalのオブジェクトをsub.pyに注入し、sub.pyではtype()を使ってAnimal型を参照しているからです。

このようにtype()を使うと実行時にオブジェクトからクラス(型)をインポートできます。
モジュールが循環参照などしている場合は解決策の1つとして使えるかもしれません。

おわりに

今回はPythonの型確認の方法について解説しました。
なにか参考になれば幸いです。

🦝 < 型チェック!

🦝 < Pythonにも型はあったんや