文字列はユーザー名やメッセージ、ログなどに欠かせない基本データ型です。
本記事では、Pythonでよく使う文字列の結合(プラス演算子の+
とstr.join()
)、そして繰り返し(乗算演算子の*
)を、初心者の方でも迷わないように順を追って解説します。
エラー例やパフォーマンスの違いも含め、実践的に学べます。
Pythonの文字列結合と繰り返しの基本
結合(+,join)と繰り返し(*)の違い
文字列の「結合」は複数の文字列をつなげて1つの文字列にする操作です。
主に+
とstr.join()
を使います。
一方で「繰り返し」は、同じ文字列を指定回数だけ並べる操作で、*
を使います。
以下に用途と特徴を簡潔にまとめます。
手段 | 主な用途 | 書き方の例 | 注意点 |
---|---|---|---|
+ | 少数の文字列を手早く結合 | "Hello, " + name | たくさんの連結には非効率、型がstr でないとTypeError |
str.join() | 複数要素(リストやタプル)の一括結合 | ", ".join(colors) | 全要素がstr である必要がある |
* | 同じ文字列の繰り返し | "=" * 30 | 負数は空文字、極端に大きい回数はメモリに注意 |
使い分けの基本ルール
- 要素があらかじめ並んでいる(リストやタプル、イテレータ)なら
str.join()
を使います。 - 少数の文字列をその場でつなぐだけなら
+
で十分です。 - 同じ文字列を繰り返すなら
*
が最も簡単で高速です。 - 区切りを挟みながら繰り返したいときは、
join
と*
を組み合わせるのが堅実です。
+(プラス)で文字列を結合
基本の使い方と例
+
は最も直感的な結合方法です。
少数の文字列をその場でつなぐ場合に向いています。
# 基本的な結合の例
first = "Hello"
second = "World"
# 単純に結合
message = first + ", " + second + "!"
print(message)
# 複数行に分けて書きたい場合は括弧で囲むと読みやすい
long_message = (
"Python " +
"String " +
"Concatenation"
)
print(long_message)
Hello, World!
Python String Concatenation
スペース・改行を足す
半角スペースや改行文字\n
を文字列として足すだけです。
視認性のために、スペースは" "
を明示して書くと読み間違いが減ります。
name = "Alice"
lang = "Python"
# スペースを挟む
s1 = name + " " + "likes" + " " + lang
print(s1)
# 改行を挟む
s2 = "1行目" + "\n" + "2行目"
print(s2)
Alice likes Python
1行目
2行目
TypeError対策(strとintの結合)
+
で結合するとき、両辺がstr
でないとTypeError
になります。
整数を混ぜたい場合はstr()
で明示的に文字列化します。
# エラー例: intをstrにしないで結合しようとするとTypeError
name = "Taro"
age = 20
try:
text = name + "は" + age + "歳です" # ここでTypeError
print(text)
except TypeError as e:
print("エラー:", e)
# 解決策1: str()で文字列化
text_ok_1 = name + "は" + str(age) + "歳です"
print(text_ok_1)
# 解決策2: joinとmap(str)を使う(全部を文字列化してから結合)
text_ok_2 = "".join([name, "は", str(age), "歳です"])
print(text_ok_2)
エラー: can only concatenate str (not "int") to str
Taroは20歳です
Taroは20歳です
str.join()で複数の文字列を結合
リストやタプルを一気に結合
str.join()
は、区切り文字となる文字列に対して呼び出し、引数のシーケンス内の全要素を結合します。
大量の要素をつなぐ場合に特に有効です。
# リスト内の単語を1つの文にする
words = ["Life", "is", "short"]
sentence = " ".join(words) # " "が区切り文字
print(sentence)
# タプルでも同様
colors = ("red", "green", "blue")
csv = ",".join(colors)
print(csv)
Life is short
red,green,blue
区切り文字(カンマ・空白・改行)
区切り文字は自由に指定できます。
改行を使えば、複数行のテキストを手早く作れます。
items = ["A", "B", "C"]
print(", ".join(items)) # カンマ+空白区切り
print(" | ".join(items)) # パイプ区切り
print("\n".join(items)) # 改行区切り
A, B, C
A | B | C
A
B
C
パフォーマンス:+より高速
多数の小さな文字列を連結する場合、+
をループで繰り返すのは非効率です。
join
は内部で必要なメモリを一度に確保するため、一般に高速です。
簡単な計測例を示します(環境により数値は変わります)。
# 大量連結の速度比較デモ
import time
parts = [str(i) for i in range(50000)]
# + を使う方法(悪い例): 毎回新しい文字列を作るため遅くなりやすい
t0 = time.perf_counter()
s_plus = ""
for p in parts:
s_plus += p
t1 = time.perf_counter()
# join を使う方法(推奨)
t2 = time.perf_counter()
s_join = "".join(parts)
t3 = time.perf_counter()
print("plusの所要時間:", t1 - t0, "秒")
print("joinの所要時間:", t3 - t2, "秒")
print("結果の長さは同じか:", len(s_plus) == len(s_join))
plusの所要時間: 0.3083496000035666 秒
joinの所要時間: 0.00026220001745969057 秒
結果の長さは同じか: True
空要素・Noneへの対応
join
は全要素がstr
であることを要求します。
空文字""
は結合できますが、空要素が多いと区切りだけが連続して見える場合があります。
また、None
が混ざるとTypeError
になります。
data = ["Alice", "", "Bob", None, "Charlie"]
# そのままjoinするとTypeError(Nonetypeが混ざっているため)
try:
print(", ".join(data))
except TypeError as e:
print("エラー:", e)
# 対策1: Noneや空文字を除外
filtered = [x for x in data if x] # 空文字とNoneを除外
print(", ".join(filtered))
# 対策2: すべて文字列化して結合(ただしNoneは"None"という文字になる)
as_str = map(str, data) # 文字列化
print(", ".join(as_str))
# 対策3: Noneは空文字に、空要素はスキップなど、方針を明示
cleaned = [x if x is not None else "" for x in data]
print(", ".join([x for x in cleaned if x != ""]))
エラー: sequence item 3: expected str instance, NoneType found
Alice, Bob, Charlie
Alice, , Bob, None, Charlie
Alice, Bob, Charlie
上の例のように、要件に応じて「空要素を残すか除外するか」「Noneをどう扱うか」を決め、前処理を行うと安全です。
*(アスタリスク)で文字列を繰り返す
基本の使い方と例
*
は同じ文字列を指定回数繰り返します。
シンプルで高速に動作します。
print("ha" * 3) # "ha"を3回
print("abc" * 0) # 0回は空文字
print("abc" * -1) # 負数も空文字
hahaha
上の実行結果で2行目と3行目は空行です。
0回や負数回は空文字になる点を覚えておくと、ガード条件を簡略化できます。
罫線・インデントの作成
繰り返しは装飾や整形に便利です。
罫線や字下げを直感的に表現できます。
title = "メニュー"
line = "=" * 20
print(line)
print(title)
print(line)
# インデント(空白4つを3回、つまり12スペース)
indent = " " * 12
print(indent + "- スタート")
print(indent + "- オプション")
====================
メニュー
====================
- スタート
- オプション
区切り付きの繰り返しはjoin
繰り返しに区切りを入れたい場合、*
だけだと末尾の区切り処理が面倒です。
join
と組み合わせると綺麗に書けます。
# 悪い例: 末尾のハイフンを消すための後処理が必要
naive = ("ha-" * 3).rstrip("-")
print(naive)
# 良い例: joinで区切りを間にだけ入れる
good = "-".join(["ha"] * 3)
print(good)
# 応用: 動的回数nに対しても同様
n = 5
print(", ".join(["ok"] * n))
ha-ha-ha
ha-ha-ha
ok, ok, ok, ok, ok
負の回数や大きな回数の注意
負の回数は空文字になります。
非常に大きな回数で繰り返すと、メモリを大量に消費しプログラムが遅くなるか、場合によってはメモリエラーになります。
サイズ感を把握しておくと安全です。
unit = "abc"
n1 = -10
n2 = 1_000_000 # 例: 100万回。実行環境により注意。
# 負数は空文字
print("負数の結果の長さ:", len(unit * n1))
# 大きな回数は長さが unit の長さ × 回数 になる
big = unit * n2
print("大きな繰り返しの長さ:", len(big))
print("先頭10文字:", big[:10])
負数の結果の長さ: 0
大きな繰り返しの長さ: 3000000
先頭10文字: abcabcabca
メモリ負荷を避ける必要がある場合は、生成しながら書き出す(ストリームに出力する)か、そもそも巨大な文字列を作らない設計を検討します。
まとめ
本記事では、文字列の結合と繰り返しの基本を整理しました。
少数の結合は+
で手軽に、多数の結合はstr.join()
で効率的に、同じ文字列の繰り返しは*
で簡潔に表現するのが基本方針です。
+
はstr
同士でしか結合できないため、数値を混ぜるときはstr()
で文字列化するか、あらかじめ全要素を整形してからjoin
を使うと安全です。
join
は空要素やNone
の扱いに注意し、必要に応じてフィルタや変換を行いましょう。
繰り返しでは0回や負数が空文字になる仕様、そして極端に大きな回数によるメモリ負荷を理解しておけば、堅実なコードが書けます。
場面ごとの得意分野を踏まえて使い分けることで、読みやすく高速な文字列処理が実現できます。