PythonではnullはNoneだった

285, 2021-07-07

目次

PythonではnullはNoneだった

Pythonではnullに相当するとオブジェクトはNoneになります。
Noneはオブジェクトの未定義の状態や、何もない状態を表現します。

結論から言うとPythonのNoneは↓のように使います。

var = None  # 変数の中身をNoneにする
print(var)
# None

def func():  # 返り値を持たない関数を定義する
    pass

result = func()  # 返り値はNone
print(result)
# None

この記事ではNoneの特性や扱い方について解説します。
具体的には↓を見ていきます。

  • nullとは?Noneとは?

  • Noneの正体

  • Noneの使い方

  • Noneにいたずらする

nullとは?Noneとは?

null(ナル)とは何も存在しないことを表すオブジェクトです。
この変数の値はnullだ、とか、この関数の返り値はnullだ、と言う風に使います。

プログラムでは「何もない」とか「存在しない」という表現にnullが慣例的に良く使われます。

たとえばC言語ではNULLというオブジェクトが存在し、これが代入されているポインタはナルポインタと呼ばれ、何も存在しないポインタという意味で使われます。
何も存在しないので、ナルポインタにアクセスするとセグフォが起きたりしてプログラムが止まったりします。
NULLの実体はただの0という整数を(void *)型にキャストしただけのもであることが多いです。

またSQLではNULLというキーワードを使ってフィールドに空の状態を設定できます。
NULLが設定されたフィールドの値は空になります。

プログラムでは明示的に「何も存在しない」という定義が必要です。
なぜならそのほうがプログラムの開発がしやすくなるからです。
「何も存在しない」という定義が存在しなければ、変数は「何も存在しない」状態を表現できなくなるため、常に何かの値が代入されている必要があります。
しかしnullがあれば、明示的に「何も存在しない」という状態を表現できるため、変数に代入しておくことが出来ます。

このようにプログラミングで使われるnullはプログラムの便宜性のために生まれました。
Pythonでもこの定義があり、nullに相当するものはNoneになります。
言語設計者が設計にnullを組み込んでいるわけです。

Noneの正体

Noneは組み込み定数と呼ばれ、どこからでも参照することが出来ます。

Noneの正体はtype()で確認できます。

print(type(None))
# <class 'NoneType'>

NoneTypeというのがNoneの型です。
このNoneTypeが生成した唯一のオブジェクトがNoneオブジェクトです。

変数にNoneを代入し、それのid()を確認すると、Noneが一意のオブジェクトであることがわかります。

a = None
b = None
print(id(a))
# 9621664
print(id(b))
# 9621664

↑の場合、変数abid()の結果が両方とも同じ値になっています。
これは変数abに代入されているオブジェクトが共にNoneだからです。
id()はオブジェクトのアイデンティティを返します。アイデンティティとはオブジェクトのユニーク性を表す整数です。
つまりアイデンティティが同じであればそのオブジェクトは同じオブジェクトであると言えます。
↑の場合は変数abのアイデンティティは同じなので、2つは同じオブジェクト(None)ということになります。

Noneの使い方

Noneの基本的な使い方です。

変数への代入

Noneは変数に代入することが出来ます。

var = None
print(var)
# None

もちろん変数から変数の代入も可能です。その場合、値は同じNoneオブジェクトになります。

a = None
b = a
print(a, b)
# None None

引数のデフォルト値

関数の引数のデフォルト値にもNoneはよく使われます。

def func(a=None):
    print(a)
    # None

func()

関数の返り値

また、returnが書かれていない関数はデフォルトでNoneを返します。

def func():
    pass

result = func()
print(result)
# None

returnが書かれていて、値が省略されている場合もNoneを返します。

def func():
    return

result = func()
print(result)
# None

Noneの比較

Noneの比較には==isが使えます。

if None == None:
    print('== none')
    # == none

a = None
if a == None:
    print('== none')
    # == none

if None is None:
    print('is none')
    # is none

a = None
if a is None:
    print('is none')
    # is none

比較には==isのどちらも使えますが、Noneがユニークなオブジェクトであることを考えるとより厳密に比較したい場合はisを使ったほうが良いでしょう。
isはオブジェクトのアイデンティティを比較します。
そのためユニークなNoneと比較すれば絶対的にNoneかどうか比較できます。
==__eq__()を定義すればその振る舞いを変更できてしまうため、厳密性に欠けると言えます。

class Animal:
    def __eq__(self, other):
        return True

a = Animal()
print(a == None)
# True

↑の場合、変数aNoneではありませんが、__eq__()==の振る舞いを変更しているため結果がTrueになっています。

リストの中のNone

リストにNoneを保存した場合、その長さはしっかり増えます。
「存在しない」が2つになるわけです。なんだか不思議ですね。

lis = [None, None]
print(len(lis))
# 2

Noneにいたずらする

Noneにいたずらはできるのでしょうか?
値を上書きしたりとか?
結論から言うとできません。
NoneはPythonから保護されています。

None += 1
# SyntaxError: 'None' is an illegal expression for augmented assignment

↑のようにNone1を加算代入しようとするとPythonから怒られます。
翻訳すると「Noneは拡張代入では不正な式です」になります。

加算代入できねーぞ、ってことね

おわりに

今回はPythonのnullNoneについて見てみました。
Pythonではnullに相当するものはNoneです。

私の人生はNone

お財布の中身はNone