PythonのNone
は、プログラムの中で「ここにはまだ値がない」「結果が見つからなかった」という状態をはっきり示すための特別な値です。
未初期化の印として使ったり、関数の戻り値に使って処理の分岐を明確にしたりと、初心者でも早い段階から出会います。
この記事では、None
の基本から判定方法、つまずきやすいエラー回避までを実行例とともに解説します。
PythonのNoneとは 何もない値の基本
Noneの意味
直感的な説明
None
は「何もない」「未設定」を表す特別なオブジェクトです。
ゼロや空文字のように「具体的な値があるけれど空っぽ」という意味ではなく、「値そのものが存在しない」という意味になります。
例(未設定を示す)
# 変数をまだ決められないときにNoneを入れておく
user = None # ログイン済みならユーザー情報が入る想定
print(user) # 何も決まっていない
print(user is None) # Noneかどうかの判定
None
True
型はNoneTypeで唯一の値
NoneTypeとは
None
の型はNoneType
です。
NoneType
のインスタンスはNone
ただ1つしか存在しません。
つまりNone
は唯一無二のシングルトンです。
例(唯一性の確認)
# Noneの型名は"NoneType"
print(type(None).__name__)
# Noneは唯一のオブジェクトなので、isで同一性比較してもTrue
a = None
b = None
print(a is b) # 同じ唯一のNoneを指している
print(a == b) # 等価比較でもTrueだが、Noneにはisを使うのが慣例
NoneType
True
True
Noneは偽になる
真偽値コンテキスト
if
文やbool()
に渡すと、None
は偽(False)として扱われます。
存在チェックや条件分岐で便利ですが、他の偽と区別したい場面ではis None
で明確に判定しましょう。
例(条件分岐)
x = None
print(bool(x)) # Falseとして扱われる
if x:
print("真です")
else:
print("偽です(Noneは偽)")
False
偽です(Noneは偽)
0や空とNoneの違い
意味の違い
0
や空文字""
、空リスト[]
は「値はあるが中身が空」という意味です。
一方、None
は「値そのものがない」です。
使い分けることで、状態の意図がコードから読み取りやすくなります。
代表的な値の比較表
値 | 型 | 意味 | 真偽値(bool(…)) | Noneかどうか |
---|---|---|---|---|
None | NoneType | 値が存在しない | False | True |
0 | int | 数量がゼロ | False | False |
“” | str | 文字数がゼロ | False | False |
[] | list | 要素数がゼロ | False | False |
False | bool | 偽という値 | False | False |
例(判定の違い)
values = [None, 0, "", [], False, "text", [1]]
for v in values:
print(
f"value={repr(v):>6}, "
f"type={type(v).__name__:>8}, "
f"bool={bool(v)!s:>5}, "
f"is None={v is None}"
)
value= None, type= NoneType, bool=False, is None=True
value= 0, type= int, bool=False, is None=False
value= '', type= str, bool=False, is None=False
value= [], type= list, bool=False, is None=False
value= False, type= bool, bool=False, is None=False
value='text', type= str, bool=True, is None=False
value= [1], type= list, bool=True, is None=False
Noneの使い方 基本パターン
未初期化の値にNone
説明
まだ値が決められないが、変数自体は用意しておきたいときにNone
を入れておきます。
後で実際の値が入ったかどうかをis None
で簡単に判定できます。
例(ログイン前後の状態)
current_user = None # まだログインしていない
if current_user is None:
print("ログインしていません")
# ログインが完了してユーザー名が入る
current_user = "alice"
if current_user is not None:
print(f"ログイン中のユーザー: {current_user}")
ログインしていません
ログイン中のユーザー: alice
戻り値がない関数はNone
説明
return
がない、またはreturn
に値を指定しない関数は自動的にNone
を返します。
戻り値を使う処理では、None
になる可能性を意識しましょう。
例(printするだけの関数)
def greet(name):
# 返り値を明示しない(=Noneが返る)
print(f"Hello, {name}!")
ret = greet("Bob")
print("返り値:", ret)
print("ret is None:", ret is None)
Hello, Bob!
返り値: None
ret is None: True
見つからないときの返り値にNone
説明
検索や取得処理で「該当なし」を表すのにNone
を返すのは定番です。
呼び出し側はis None
で見つからなかったケースを分岐できます。
例(最初に見つかった偶数の位置を返す)
# 見つかればインデックス(int)、なければNoneを返す
def find_first_even(nums):
for i, n in enumerate(nums):
if n % 2 == 0:
return i
return None # 見つからなかった
print(find_first_even([1, 3, 5])) # None
print(find_first_even([1, 3, 6, 7])) # 2
idx = find_first_even([1, 3, 5])
if idx is None:
print("偶数は見つかりませんでした")
else:
print(f"最初の偶数の位置: {idx}")
None
2
偶数は見つかりませんでした
デフォルト引数はNoneで遅延初期化
典型パターン
ミュータブル(書き換え可能)なオブジェクトをデフォルト引数に直接置くと、関数呼び出し間で「共有」される落とし穴があります。
None
を置いて、関数内で新規作成する「遅延初期化」が安全です。
悪い例(リストが共有されてしまう)
# 悪い例: デフォルトのリストは関数定義時に1度だけ作られ、呼び出し間で共有される
def append_item_bad(item, bucket=[]):
bucket.append(item)
return bucket
print(append_item_bad("A")) # 期待: ["A"]
print(append_item_bad("B")) # 期待: ["B"] だが実際は["A", "B"]に溜まる
['A']
['A', 'B']
良い例(Noneで遅延初期化)
# 良い例: Noneをデフォルトにして、必要なときに新規作成する
def append_item_good(item, bucket=None):
if bucket is None:
bucket = [] # 呼び出しごとに新しいリスト
bucket.append(item)
return bucket
print(append_item_good("A")) # ["A"]
print(append_item_good("B")) # ["B"]
print(append_item_good("C", ["X"])) # 既存のリストを渡すこともできる
['A']
['B']
['X', 'C']
Noneの判定と比較 isを使うのが基本
None比較はisを使う
isと==の違い
is
は「同一のオブジェクトか」を調べ、==
は「等しいか」を調べます。
==
はクラスによって振る舞いが上書きされ得るため、None
の判定は常にis
(またはis not
)を使うのが安全です。
例(==が誤解を招くケース)
class AlwaysEqual:
# どんな相手とも等しいと答える、極端な実装
def __eq__(self, other):
return True
obj = AlwaysEqual()
print(obj == None) # Trueになってしまう(等価演算子が上書きされているため)
print(obj is None) # False(同一オブジェクトではない)
True
False
if x is None と if not x の違い
説明
if not x
は0
や""
、[]
、False
など「空や偽の値」もまとめて偽と見なします。
None
だけを区別したいときはif x is None
を使います。
例(混同しないための比較)
tests = [None, 0, "", [], False, 1]
for x in tests:
print(
f"x={repr(x):>4}, not x -> {not x}, x is None -> {x is None}"
)
x=None, not x -> True, x is None -> True
x= 0, not x -> True, x is None -> False
x= '', not x -> True, x is None -> False
x= [], not x -> True, x is None -> False
x=False, not x -> True, x is None -> False
x= 1, not x -> False, x is None -> False
Noneを返す関数の扱い
型ヒントで明示する
int | None
(Python 3.10以降)やOptional[int]
(typing)のように、戻り値がNone
になる可能性を型で示すと、呼び出し側でのチェック漏れを減らせます。
例(パースに失敗したらNone)
# 文字列が整数ならint、失敗したらNoneを返す
def parse_int(s: str) -> int | None:
try:
return int(s)
except ValueError:
return None
for text in ["42", "forty two"]:
n = parse_int(text)
if n is None:
print(f"{text!r} は整数に変換できません")
else:
print(f"{text!r} -> {n} (n+1={n+1})")
'42' -> 42 (n+1=43)
'forty two' は整数に変換できません
Noneの注意点とよくあるエラー
Noneにメソッドを呼んで失敗
エラーの例と対策
None
はメソッドを持ちません。
None.upper()
のような呼び出しはAttributeError
になります。
値がNone
の可能性があるなら、先にガードしましょう。
s = None
# そのまま呼ぶとエラーになるが、ここでは例外を捕捉して表示
try:
print(s.upper())
except Exception as e:
print(type(e).__name__, ":", e)
# 安全な呼び方の一例
def safe_upper(text: str | None) -> str:
if text is None:
return "" # 仕様に合わせて空文字などを返す
return text.upper()
print("安全な結果:", safe_upper(s))
print("安全な結果:", safe_upper("hello"))
AttributeError : 'NoneType' object has no attribute 'upper'
安全な結果:
安全な結果: HELLO
Noneとの演算でTypeError
エラーの例と対策
None + 1
のような演算は定義されておらずTypeError
になります。
演算前にNone
かどうかを確認し、置き換えるか分岐しましょう。
x = None
try:
print(x + 1)
except TypeError as e:
print(type(e).__name__, ":", e)
# ガードしてから使う
x = 0 if x is None else x
print("計算結果:", x + 1)
TypeError : unsupported operand type(s) for +: 'NoneType' and 'int'
計算結果: 1
早期returnでNoneが混ざる
説明
関数の分岐のどこかでreturn
を書き忘れて、暗黙にNone
が返ることがあります。
呼び出し元で数値計算に使ってTypeError……というのはよくあるミスです。
すべての分岐で戻り値の型を揃えましょう。
例(バグのある実装と修正版)
# バグのある実装: 負値のときに値を返していない(=None)
def discounted_price(price: float) -> float | None:
if price < 0:
return # Noneが返る
if price > 100:
return price * 0.9
return price
# 問題の再現
p = discounted_price(-5)
print("戻り値:", p)
try:
print("合計:", p + 10) # TypeError
except TypeError as e:
print(type(e).__name__, ":", e)
# 修正版: すべての経路でfloatを返す
def discounted_price_fixed(price: float) -> float:
if price < 0:
return 0.0 # 仕様として0に丸めるなど、一貫した型を返す
if price > 100:
return price * 0.9
return price
p2 = discounted_price_fixed(-5)
print("修正版の合計:", p2 + 10)
戻り値: None
TypeError : unsupported operand type(s) for +: 'NoneType' and 'int'
修正版の合計: 10.0
まとめ
None
は「値が存在しない」状態を表す唯一のオブジェクト(NoneType)で、真偽値コンテキストでは偽として扱われます。
0
や空文字と混同せず、意味の違いを意識することが読みやすいコードにつながります。
判定は==
ではなくis
(またはis not
)を使い、if not x
ではなくif x is None
で明確に分岐しましょう。
典型パターンとしては、未初期化の印、見つからないときの返り値、そしてデフォルト引数の遅延初期化が挙げられます。
よくあるエラー(メソッド呼び出しや演算での例外、早期returnでのNone
混入)は、事前のガードと一貫した戻り値設計、そして型ヒントの活用で防げます。
まずは本記事のサンプルを写経し、None
を安全に扱う感覚を身につけてください。