Pythonの型とオブジェクトを知ろう
Pythonでは、intやfloat、str、boolといった基本的なデータ型もすべて「オブジェクト」であり、それぞれに特徴的な振る舞いや性質があります。プログラミングを始めたばかりの方にとっては「型」と聞くと堅苦しい印象かもしれませんが、Pythonの型は比較的シンプルで、しかも柔軟性が高いという特徴があります。そこで本記事では、初心者の方に向けて、代表的な基本型をオブジェクトとして理解するうえで知っておきたいポイントを整理しながら解説していきます。
Pythonにおける「すべてがオブジェクト」の考え方
まず、大前提としてPythonでは「すべてのデータがオブジェクトである」と定義されています。これは「データを操作するときに、オブジェクトとしての振る舞いやプロパティを利用できる」ということを意味します。たとえば、文字列に対してstr.upper()
といったメソッド呼び出しができるのは、文字列もオブジェクトとして定義されているためです。整数や浮動小数点数、真偽値といった基本的な値も例外ではなく、Pythonの世界では例外なくオブジェクトとして扱われます。
int型(整数型)
Pythonのint型は、一般的に「整数」を表すオブジェクトです。他の言語ではあらかじめビット幅(32ビットや64ビットなど)が固定されており、扱える最大値や最小値が決まっている場合がありますが、Pythonのint型は基本的にメモリが許すかぎり大きな値や小さな値を扱えます。
- 負の数も正の数も区別なく同じ
int
型 - 2進数や8進数、16進数表記も
int
型として扱われる
たとえば、2進数の0b
や16進数の0x
を使った表記も、Pythonでは自動的にint型に変換されます。
# 10進数での整数
x = 42
print(x, type(x)) # 42
# 2進数の表記(0b)
y = 0b101010
print(y, type(y)) # 42
# 16進数の表記(0x)
z = 0x2A
print(z, type(z)) # 42
いずれも結果は同じint
型ですが、内部的にはPythonがそれを整数オブジェクトとして解釈し、メモリ上にオブジェクトを生成しています。
float型(浮動小数点数型)
続いてfloat型は、いわゆる「小数点を含む数値」を表すオブジェクトです。C言語などでは厳密に「単精度」「倍精度」などがあり、値の表現範囲が細かく規定されていますが、Pythonのfloatは実質的に「倍精度(64ビットの浮動小数点数)」として実装されています。数値計算をする際、float型の計算では丸め誤差が発生することがありますが、これは浮動小数点数の宿命といえるでしょう。
例として、小数を扱う際の注意を示しておきます:
a = 0.1
b = 0.2
c = a + b
print(c) # 0.30000000000000004 のような結果になる場合がある
このようにPythonのfloatは数学的な小数演算をそのまま厳密に表せるわけではありません。より正確な小数演算が必要な場合は、decimal
モジュールを使用するのがおすすめです。ただし、通常の用途ではfloat型で十分なことが多いでしょう。
bool型(真偽値型)
bool型は、論理値としてTrueまたはFalseを持つオブジェクトです。Python内部では、True
とFalse
は実はint
を継承しており、True == 1
、False == 0
が成り立ちます。そのため、条件式の結果を数値演算に組み込むようなテクニックも可能ですが、可読性の観点からはあまり多用するのはおすすめしません。
is_active = True
print(is_active, type(is_active)) # True
# boolはintのサブクラス
print(int(True)) # 1
print(int(False)) # 0
Pythonでは、条件分岐だけでなく様々な場面でbool型が登場します。「すべてのオブジェクトには真偽値の評価がある」というのもPythonの特徴で、たとえば空文字列や0はFalse、それ以外はTrueとみなされます。
str型(文字列型)
文字列を表すstr型も、立派なオブジェクトです。文字列連結の+
演算や、文字列メソッド(.upper()
, .lower()
, .replace()
など)を利用できるのは、strがオブジェクトとして多様な機能を持っているからです。Python 3系では、strはUnicode文字列として扱われますので、日本語も含めてほぼどんな文字でも同じように扱えます。
ただし、str型は不変(immutable)なオブジェクトであるため、以下のようなコードでは新しい文字列オブジェクトが作られる点に注意しましょう。
s1 = "Hello"
s2 = s1 + " World"
print(s1) # "Hello"
print(s2) # "Hello World"
# s1は変化しないが、s2には新しい文字列オブジェクトが代入される
イミュータブル(immutable)とミュータブル(mutable)
前述のとおり、strやint
、float
、bool
などの基本型は「イミュータブルなオブジェクト」です。つまり、一度生成されると内容を変更できません。変更が必要な場合は、新たなオブジェクトを生成します。list
やdict
などは逆に「ミュータブル」なオブジェクトであり、内容を書き換えることが可能です。このイミュータブルかミュータブルかという性質は、オブジェクトの取り扱い方を理解するうえで非常に重要です。
イミュータブルな基本型を使っている限りは、「変更による思わぬ影響」を受けづらいという利点があります。一方で、大量の連結を繰り返すような文字列操作などではパフォーマンス面でミュータブルな型を使った方がよいケースもあります。用途や場面に応じて、この違いを意識するとよいでしょう。
オブジェクトのIDを確認する: id()
関数
Pythonには、オブジェクトごとに割り振られる「ID」があります。これは実装依存ではありますが、通常はメモリアドレスに関連づけられていると考えて問題ありません。id()
関数を使うことで、変数に格納されたオブジェクトがどのIDを持っているかを確認できます。
a = 10
b = 10
print(id(a))
print(id(b))
上記のように、a
とb
が同じ数値を持つint
オブジェクトなら、Pythonの実装によっては同じIDを指している場合があります。これは「小さな整数をキャッシュして使い回す」という最適化が行われているためです。こうした最適化の存在から、イミュータブルなオブジェクトは「同じ値の場合には再利用される」ケースがあるという点も、Pythonの型を理解するときには押さえておきたいポイントです。
まとめ
Pythonでは、int、float、str、boolなど、私たちが普段よく使う基本型もすべてオブジェクトとして扱われます。オブジェクトとしての性質があるからこそ、これらに対してメソッドを呼び出したり、他の型との相互変換を行ったりといった柔軟な操作が可能になるのです。加えて、Pythonのイミュータブルとミュータブルの概念は、オブジェクトの取り扱いをシンプルにするうえで欠かせません。
これらの基本型を「ただの数字・文字列」ではなく、「オブジェクト」として意識できるようになると、Pythonにおける型の仕組みやオブジェクト指向の考え方に一歩踏み込んだ理解が得られます。ぜひ自分でコードを書きながら、type()
やid()
などの組み込み関数も活用して、Pythonのオブジェクトと型の世界をより深く探求してみてください。