こんにちは、PyQサポートです。
今回は AttributeError: 'NoneType' object has no attribute 'group'
というエラーの意味と、その解消方法を解説します。
re
モジュールを使った時に、このエラーになることがあります。
早速、質問を見ていきましょう。
- 質問 AttributeError: 'NoneType' object has no attribute 'group'というエラーはどういうものですか?
- 回答 検索パターンにマッチしない場合を考慮していないために起きたエラーです
- 参考リンク
質問 AttributeError: 'NoneType' object has no attribute 'group'
というエラーはどういうものですか?
AttributeError: 'NoneType' object has no attribute 'group'
というエラーが出ました。どのように直したら良いでしょうか?
入力した内容(コード)
import re text = "Hello" m = re.match("Hi", text) print(m.group(0))
出たエラー(実行結果)
Traceback (most recent call last): File "/Users/pyq/scripts/match.py", line 5, in <module> print(m.group(0)) AttributeError: 'NoneType' object has no attribute 'group'
回答 検索パターンにマッチしない場合を考慮していないために起きたエラーです
AttributeError: 'NoneType' object has no attribute 'group'
は、AttributeError
(属性エラー)というエラーで、そのオブジェクトに存在しない属性を参照しようとすると発生するエラーです。
今回の場合はm
がNone
オブジェクトであったため、このエラーが発生しました。
(None
は「何もない」ことを表すオブジェクトであり、属性を持ちません)
ではなぜ m
がNone
だったのでしょうか?
それには、re
モジュールのmatch()
関数について知る必要があります。
match()
関数の使い方
re
モジュールのmatch()
関数の基本的な使い方は以下のとおりです(import re
は省略しています)。
マッチ結果 = re.match(検索パターン, 対象文字列)
match()
関数は「対象文字列」の先頭部分が「検索パターン」とマッチすれば、マッチ結果として「マッチオブジェクト」を返します。
しかし、マッチしないとNone
を返します。
今回のコードでは、"Hi"
は"Hello"
と先頭部分がマッチしないため、マッチ結果であるm
はNone
になりました。
text = "Hello" m = re.match("Hi", text) # m は None になる
m
がNone
なので、m.groups(0)
でAttributeError
が発生します。
このように検索パターンにマッチしない場合を考慮していなかったことが、今回のエラーの原因といえるでしょう。
マッチしなかった場合にエラーを回避するには
このエラーを回避する方法は、大きく2つあります。
1つは、try ... except
文を使って、AttributeError
を処理する方法です。もう1つは、Python 3.8から導入された代入式を使う方法です。
代入式を使うほうがシンプルに書けますので、今回はこちらの方法を紹介します。
代入式は:=
(セイウチ演算子と呼ばれます)を使って記述され、変数に値を代入するとともに、代入結果を返します。
代入式を使って修正したコードは以下のとおりです(このコードは実行しても何も表示されません)。
import re text = "Hello" if m := re.match("Hi", text): print(m.group(0))
m := re.match("Hi", text)
が代入式を使っている箇所です。マッチ結果がNone
の場合、if
文の判定でFalse
扱いとなります。そのためm.group(0)
は実行されず、エラーを回避できます。
ちなみに、代入式の部分を代入式を使わずに書くと、以下のようになります。
# 代入式を使わないと2行になる m = re.match("Hi", text) if m: print(m.group(0))
代入式により「文字列検索」と「マッチ結果の判定」を1行で記述でき、コードをより簡潔に書けることが分かると思います。
なお、代入式については過去のブログ記事でも解説していますので、下部の参考リンクをご参照ください。
補足: match()
関数とsearch()
関数
今回の例ではre
モジュールのmatch()
関数を使いましたが、re
モジュールにはsearch()
関数というものもあります。
基本的な使い方はmatch()
関数と同じです。
マッチ結果 = re.search(検索パターン, 対象文字列)
この2つの関数の違いは、match()
関数が文字列の先頭がパターンにマッチするかを調べるのに対し、search()
関数は先頭に限らずマッチする部分があるかを調べるところです。
場合に応じて使い分けるとよいでしょう。
参考リンク
match()
関数の公式ドキュメント
search()
関数の公式ドキュメント
group()
関数の公式ドキュメント
代入式についての過去のブログ記事