結論:str()の失敗ではなく、文字列へNoneを直接連結した
"Hello, " + NoneではTypeErrorになります。一方str(None)自体は文字列"None"を返します。まず値の返り元とNoneが許可される仕様かを確認し、例外を消すだけの空文字/f-stringへの置換で必須値の欠落を隠さないようにします。
値を出力する前の判断
| 入力/操作 | 区別すること |
|---|---|
| 欠落キー | dict.getのdefaultはキーがない場合。明示Noneとは別 |
| None | 任意値の代替表示か、必須値不正として拒否かを決める |
| 空文字/0/False | orはこれらも置換する。Noneだけの判定とは違う |
| str/f-string | 表示形式を変えるだけで、欠けた値を復元しない |
| re.match失敗 | None.groupの呼出しなら、連結前にAttributeError |
| list.append | 戻り値はNone。元listの変更と表示対象を分ける |
任意表示・明示null・必須設定を分けた実行例
次はPython3.12.10の標準ライブラリだけの例です。optional_labelはNoneだけをGuestにし、空文字は保持します。nickname_or_guestは欠落キーをGuestにしますが、明示Noneを拒否します。これは一例の仕様で、業務上nullを許可する場合はその条件を明示してください。required_hostは必須値を黙ってlocalhostに変えず拒否し、実通信や環境変数の変更はしません。
import re
def optional_label(value: str | None, fallback: str = 'Guest') -> str:
if value is None:
return fallback
if not isinstance(value, str):
raise TypeError('label must be str or None')
return value
def nickname_or_guest(user: dict) -> str:
if 'nickname' not in user:
return 'Guest'
value = user['nickname']
if value is None:
raise ValueError('nickname was explicitly null')
if not isinstance(value, str):
raise TypeError('nickname must be str')
return value
def required_host(settings: dict) -> str:
value = settings.get('HOST')
if value is None or (isinstance(value, str) and not value.strip()):
raise ValueError('HOST is required')
if not isinstance(value, str):
raise TypeError('HOST must be str')
return value
def found_number(text: str) -> str:
match = re.match(r'(\d+)', text)
if match is None:
return 'Not found'
return 'Found: ' + match.group(1)
if __name__ == '__main__':
print('Hello, ' + optional_label(None))
print('Empty stays empty:', repr(optional_label('')))
print('Missing key:', nickname_or_guest({}))
print(found_number('123abc'))
print(found_number('abc'))
実行例の結果はHello, Guest、空文字は''、欠落キーはGuest、regexはFound: 123/Not foundでした。型ヒントだけでは実行時に型が強制されないため、この例では必要な型判定も書いています。秘密値を含む実際の設定全文をprintして調査しません。
旧コードを読む際の訂正
既存の10コード例と元の5黒コード表は保持します。dict.getにdefaultを書いても、キーが存在して値がNoneならdefaultは使われません。name or "ゲスト"はNone限定ではなく空文字等も置き換えます。戻り値がない関数と未定義変数のNameError、未マッチのregexのAttributeErrorを同じTypeErrorとして扱いません。
通常のf"{None}"は表示できますが、すべてのformat指定がNoneに使えるわけではありません。検体では幅指定f"{None:>8}"はTypeErrorでした。format/strが通ることと、入力の型/必須性/意味が正しいことは別です。Pythonの+全般を「同じ型しか使えない」と一般化もしません。
調査から再発防止まで
- tracebackで失敗した演算と値の生成元を特定する。実値に秘密情報がある場合は型/有無など必要項目だけを記録する。
- 戻り値のすべての経路、dictの欠落/明示None、設定の未指定等を確認する。Noneを空文字へ変える前に仕様を決める。
- 許可する場合だけ代替表示し、必須値/型違いは適切な場所で拒否する。広いexceptで握りつぶさない。
- None/欠落/空文字/正常値/不正型の試験を追加する。型ヒント/静的検査だけで入力検証を完了したとは扱わない。
エラー分類はPythonエラー一覧を参照。既存の辞書型を文字列へ変換する方法も保持しますが、辞書の文字列化は欠落値の修復ではありません。
既存のパターン別資料
| この記事の要点 |
|---|
|
エラーの意味
Python で以下のようなコードを書くと発生:
旧例の注意:strにNoneを直接足す例です。str(None)自体が失敗するという意味ではありません。
name = None
greeting = "Hello, " + name
# TypeError: can only concatenate str (not "NoneType") to str
ここでの文字列連結はstrとNoneを直接足せないという意味です。Pythonの+全般を同じ型だけと一般化せず、intとfloat等の演算と分けます。文字列 "Hello, " と None を直接 + するとこのエラーになります。
よくある原因パターン
パターン 1: 関数の return 書き忘れ
旧例の注意:通常の関数でreturnを省略した経路はNoneになります。すべての戻り経路と呼出し側の必須性を確認します。
def get_name():
name = "Alice"
# return を書き忘れ → 戻り値は None
result = "User: " + get_name()
# TypeError: ...
# 修正:
def get_name():
name = "Alice"
return name # ← 追加
パターン 2: dict.get() で存在しないキー
旧例の注意:dict.getのdefaultは欠落キーに使われます。キーが存在して値がNoneなら、この修正だけでは解決しません。
user = {"name": "Alice"}
greeting = "Hello, " + user.get("nickname")
# get() は存在しないキーで None を返す → TypeError
# 修正:
greeting = "Hello, " + user.get("nickname", "ゲスト") # デフォルト値
パターン 3: 環境変数が未設定
旧例の注意:未設定と空文字/不正値を区別します。HOSTが必須ならlocalhostへ黙って変更せず、必要な場所で拒否します。実環境の秘密値は公開しません。
import os
host = os.environ.get("HOST") # 環境変数 HOST が未設定なら None
url = "http://" + host + "/api"
# TypeError
# 修正:
host = os.environ.get("HOST", "localhost") # デフォルト値
パターン 4: 関数呼び出しが副作用のみ(list.append 等)
旧例の注意:この元例はstr(appendの戻り値)なので連結自体は成功し、Items: Noneになります。listの変更と戻り値を別に扱います。
items = []
result = "Items: " + str(items.append("a"))
# list.append() は None を返す → str(None) は "None" だが、生 None を + すると TypeError
# 修正:
items.append("a")
result = "Items: " + str(items)
パターン 5: 正規表現で match しない
旧例の注意:未マッチのm.group(1)は、連結より先にAttributeErrorになります。TypeErrorと同じ原因/例外として案内せず、m is Noneを先に確認します。
import re
m = re.match(r"(\d+)", "abc") # マッチしないと None
value = "Found: " + m.group(1)
# m is None → AttributeError もしくは TypeError
# 修正:
m = re.match(r"(\d+)", "abc")
if m:
value = "Found: " + m.group(1)
else:
value = "Not found"
対処方法
方法 1: None チェック
旧例の注意:is Noneとorは同じ条件ではありません。orは空文字/0/False等も置換します。空文字を残す仕様ならNoneだけを判定します。
name = get_name()
if name is None:
name = "ゲスト"
greeting = "Hello, " + name
# または or 演算子で短く
greeting = "Hello, " + (name or "ゲスト")
方法 2: str() で明示変換
旧例の注意:文字列Noneへ表示変換できても、必須値の欠落は直りません。意図した画面/CSV表現かを確認します。
name = get_name() # None かもしれない
greeting = "Hello, " + str(name)
# → "Hello, None" (エラーにならない)
方法 3: f-string を使う(表示形式の選択)
旧例の注意:通常のf-stringの表示例であり、全format指定/任意objectで例外が出ない保証ではありません。欠落値の意味を先に確認します。
name = None
greeting = f"Hello, {name}"
# → "Hello, None" (エラーにならない、自動で str 化)
方法 4: format() メソッド
旧例の注意:format()も表示形式の選択です。必須性/型の検証の代わりにせず、使用するformat指定を別に確認します。
name = None
greeting = "Hello, {}".format(name)
# → "Hello, None"
類似エラー(要注意)
| エラーメッセージ | 意味 |
|---|---|
can only concatenate str (not "int") to str | int を文字列に連結(str(int_val) で変換) |
can only concatenate list (not "str") to list | list と str を連結(list + [str] で対応) |
unsupported operand type(s) for +: 'NoneType' and 'str' | 左辺が None の場合(順序逆) |
AttributeError: 'NoneType' object has no attribute ... | None に対してメソッド呼び出し |
予防策
- 型ヒント (Type Hints) を使う: 関数の戻り値型を明示すれば IDE が None の可能性を警告
- mypy で静的型チェック:
Optional[str]等を使い分けて事前に検出 - None を返す関数は明示的にチェック:
dict.get,re.match,list.append等。Pythonのlist.findというAPIはない - 値の仕様を明示する: None/空文字/空listを別の意味として扱い、初期値を変えるだけで欠落を隠さない
- f-string を活用: 表示変換と必須値/型の検証を分ける。すべてのformat指定がNoneへ使えるわけではない
関連記事
元の書式付き資料
元例の注意:元のPython例です。get_name/fetch_nameは説明用の未定義関数です。orはNone以外のfalsy値も置換するため、必須値を空文字へ隠す定型対処には使いません。
|
can only concatenate str (not "NoneType") to str |
元例の注意:元のPython例です。get_name/fetch_nameは説明用の未定義関数です。orはNone以外のfalsy値も置換するため、必須値を空文字へ隠す定型対処には使いません。
|
name = None message = "user: " + name |
元例の注意:元のPython例です。get_name/fetch_nameは説明用の未定義関数です。orはNone以外のfalsy値も置換するため、必須値を空文字へ隠す定型対処には使いません。
|
name = get_name() if name is None: name = "" message = "user: " + name |
元例の注意:元のPython例です。get_name/fetch_nameは説明用の未定義関数です。orはNone以外のfalsy値も置換するため、必須値を空文字へ隠す定型対処には使いません。
|
name = get_name() or "" message = "user: " + name |
元例の注意:元のPython例です。get_name/fetch_nameは説明用の未定義関数です。orはNone以外のfalsy値も置換するため、必須値を空文字へ隠す定型対処には使いません。
|
def get_name(): value = fetch_name() return value if value is not None else "" |
確認範囲と一次資料
Python3.12.10と専用venvのNotebook7.6.3/Server2.21.1、空設定/専用rootのローカル検体で確認した範囲です。本番や利用者の設定/保存済みnotebook・kernel・認証を変更していません。全版/全拡張/実ブラウザ・SSH/conda/全OS・実際のkernel修復やセル実行の保証ではありません。
- Jupyter Serverの認証/セキュリティ / Notebookの問題切分け / Notebook7のserver移行
- Python3.12の組込み型/真偽値/dict / re.match / 型ヒントと実行時の違い
子ページはありません
- ModuleNotFoundError: No module named '~'; '~' is not a package
- pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available
- ...AppData/Local/Microsoft/WindowsApps/python: Permission denied
- 【pycharm】connecting to console が終わらない
- can only concatenate str (not "NoneType") to str
- can only concatenate str (not "datetime.datetime") to str
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスのソフト一覧|Blender・Metasequoiaと用途別の選び方
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Visual Studio「デザイナーを表示できません」エラーの原因と対処 2026-10-28 12:06:00
- SSH 認証に失敗しました。再試行してください の対処 2026-10-28 12:06:00
- SSH2 秘密鍵の読み込みに失敗しました の原因と対処 2026-10-28 12:06:00
- TeraTerm のよくあるエラーと対処法完全ガイド — Connection refused / 2026-10-28 12:06:00
- Visual Studio エラー一覧|コンパイルエラー・警告の確認方法と対処 2026-10-28 11:39:57
- Whitelabel Error Page の原因と消し方|Spring Boot のエラーページ 2026-10-28 11:39:57
- Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法 2026-10-28 11:39:57
- SQL WHERE 句完全ガイド 2026-10-28 11:39:57
- SQL JOIN 完全ガイド (INNER/LEFT/RIGHT/FULL OUTER) 2026-10-28 11:39:57
- tomcat の起動 / 停止ログと catalina.log・catalina.out の違い 2026-10-28 10:24:23
- Tomcat の起動確認方法 5 つ|localhost:8080・ポート・プロセス・ログ 2026-10-28 10:24:23
- Oracle 19c COMMITの使い方: 暗黙コミット・自動確定・応答不明時の確認 2026-10-28 09:59:09
- Oracle 19c DELETE文|削除対象の確認・COMMIT前の判断・ROLLBACKの条件 2026-10-28 09:59:09
- Oracle 19c INSERT文|INSERT ALL・SELECT・RETURNINGとMERGEの使い分け 2026-10-28 09:59:09
- Oracle 19cのトランザクション制御|COMMIT・ROLLBACK・分離レベルと接続設定 2026-10-28 09:59:09