nikkie-ftnextの日記

イベントレポートや読書メモを発信

Pythonでtypeの返り値を型と比較する(例:valueがint型か知りたいときにtype(value) == intとする)のはいかんぜよ

はじめに

ぶっぶーですわ!🙅‍♂️1 nikkieです。

表題の件について見ていきましょう。
某書籍レビューでお見かけして、記憶に刻まれた思い出があります。

目次

動作環境

pip install flake8で以下が入りました

mccabe      0.7.0
pycodestyle 2.11.0
pyflakes    3.1.0

flake8 「ぶっぶーですわ!」

E721が送出されます。

value = 108
if type(value) == int:
    print("整数です")
% python okorare.py
整数です
% flake8 okorare.py
okorare.py:2:4: E721 do not compare types, for exact checks use `is` / `is not`, for instance checks use `isinstance()`

なぜダメか ー サブクラスを考慮しないから

組み込み関数typeのドキュメントより
https://docs.python.org/ja/3/library/functions.html#type

オブジェクトの型の判定には、 isinstance() 組み込み関数を使うことが推奨されます。これはサブクラスを考慮するからです。

組み込み関数isinstanceのドキュメント2
https://docs.python.org/ja/3/library/functions.html#isinstance

object 引数が classinfo 引数に指定した型、またはその (直接、間接、または 仮想 の) サブクラスのインスタンスである場合に True を返します。

サブクラスを考慮しないことを確かめる

class User:
    ...


class RoyalUser(User):
    ...


user = User()
if type(user) == User:
    print("userはUserです")
royal_user = RoyalUser()
if type(royal_user) == RoyalUser:
    print("royal_userはRoyalUserです")
if type(royal_user) == User:
    print("royal_userはUserです")

RoyalUserはUserのサブクラスです。
ですが、type(royal_user) == UserFalseを返します(サブクラスを考慮していない!)

% python okorare.py
userはUserです
royal_userはRoyalUserです

isinstanceはサブクラスを考慮!

typeの代わりにisinstanceを使うように書き換えます。

user = User()
if isinstance(user, User):
    print("userはUserです")
royal_user = RoyalUser()
if isinstance(royal_user, RoyalUser):
    print("royal_userはRoyalUserです")
if isinstance(royal_user, User):
    print("royal_userはUserです")
% python okorare.py
userはUserです
royal_userはRoyalUserです
royal_userはUserです

「royal_userはUserです」がありますね。
isinstance(royal_user, User)Trueサブクラスを考慮している

pycodestyleが「ぶっぶーですわ!」

flake8は、pyflakes・pycodestyle・mccabeが三位一体となった静的解析ライブラリです。
送出するエラーコードについて
https://flake8.pycqa.org/en/latest/user/error-codes.html

  • pyflakesが送出するのは、F
  • mccabeは、C
  • pycodestyleは、EとW

「E721 do not compare types」はpycodestyleによるのですね。
https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes

E721 do not compare types, use ‘isinstance()’

PEP 8にも書いてありました

冒頭で紹介したFlake8 RulesからPEP 8にリンクがありました。
Programming Recommendations」の中に

Object type comparisons should always use isinstance() instead of comparing types directly:

意訳 オブジェクトの型の比較は、型を直接比較する代わりに常にisinstanceを使うべき

PEP 8でかなり強く「ぶっぶーですわ」と言っていたのですね

終わりに

オブジェクトの型を比較したいときに、typeの返り値を型と比較するのはぶっぶーですわ!🙅‍♂️
代わりにisinstanceを使いましょう。サブクラスも考慮してくれます

  • pycodestyle (flake8)「ぶっぶーですわ!」
  • 組み込み関数typeのドキュメント「ぶっぶーですわ」
  • PEP 8「ぶっぶーですわ!!」

OSSのコードを読んでいるとisinstanceは頻出な書き方という印象です。
私はisinstanceに慣れきっているのですが、気を張っていなくてもflake8(ツール)が教えてくれますね。

P.S. 本日は皆さま、お誕生日おめでとうございます

入れ替えたら1/8ですからね!


  1. マスク氏も大好き🙅‍♂️。ダイヤさん推しが高じて、1つのサービスをここまで変えちゃうとは
  2. 脱線ですが、ドキュメントからisinstanceの第2引数には型を詰めたタプルを渡せると知って「ほえ〜」となりました