Base64 形式を扱う必要がありますか?それならこのサイトが最適です!データをエンコードまたはデコードするために便利なオンラインツールをご利用ください。

Python での Base64 エンコード:完全ガイド

これが表裏一体のもう片方の顔です。あなたの手の元にはデータがあります - ファイル、パスワードのペア、バイナリの塊、Unicode の 1 段落 - そして下流のどこかで、それは文字しか受け入れないチャネルを通過しなければなりません。それが Base64 の仕事のすべてです:データ 3 バイトを 64 文字のアルファベットから選んだ 4 文字に書き換え、最後の組に = を足して 4 つごとのまとまりにし、文字を渡す。このサイトのホームページはアルファベットまで含めて形式を完全に説明しているので、そこは 1 息で済ませて、残りの時間は Python が実際に何をするかに使います。

始める前に、経済性について正直な一文を。この数字は、この話題のあらゆる会話に登場するからです:テキストとしての安全性の代償はサイズです。Base64 はデータを約 3 分の 1 膨らませ、入力 3 バイトにつき文字 4 つなので、1 メガバイトのバイナリは 1 メガバイトと 3 分の 1 の文字になります。トークンや設定値なら大した問題ではありませんが、動画ファイルなら、選択肢を考える理由になります。

そして朗報です:Python の答えは、1 つのインポートと 1 つの関数です。base64.b64encode は数十年にわたって標準ライブラリにいて、インストール不要、内部は C の速さで動きます。このガイドの残りは、ワンライナーを実世界で役に立たせる長い尻尾です:全 TypeError バグの半分を止めるバイトのみのルール、URL 安全アルファベット、MIME の行折り返しツール、そして Base64 が静かに仕事をこなしているプロトコルたち - JWT、HTTP ヘッダー、WebSocket ハンドシェイク、メール、PEM、data URL。

b64encode と出会う

契約は 4 つの文に収まります。1 つ目:入力はバイト風オブジェクト - bytes、bytearray、memoryview - で、プレーンな文字列は拒否されます。2 つ目:出力は bytes オブジェクトで、決して str にはなりません。3 つ目:出力は常に 4 文字の倍数にパディングされるので、入力 1 バイトでも Zg== ができます。4 つ目:出力は 1 行だけで、入力がどんなに大きくても決して折り返されません。この記事の残りは、その 4 つの文への注釈です:

import base64
encoded = base64.b64encode(b"foobar")
print(encoded)
# b'Zm9vYmFy'
print(len(encoded))
# 8

URL やヘッダーや JSON フィールドのために実際の文字列が欲しいなら、結果を ASCII としてデコードしてください。アルファベットは、それ以外が入り得ないことを保証するので、このステップは安全で安価です:

import base64
text = base64.b64encode(b"foobar").decode("ascii")
print(text)
# Zm9vYmFy

シグネチャにはもう 1 つ、altchars という引数があります。これは標準アルファベットの + と / を別の文字のペアに差し替えます。まさに URL 安全変種の裏にあるノブです。その考えをしばらく取っておいてください。あと数セクションで、トークンとクエリ文字列の話をするときに再会します。

型の壁:str は bytes ではない

この記事で最初に出会う、Python 特有の壁は型システムで、感じておく価値があります。b64encode は、この言語の中でも最も寛容ではないエラーメッセージの 1 つで文字列を拒否します:

import base64
try:
  base64.b64encode("hello")
except TypeError as caught:
  print(caught)
# a bytes-like object is required, not 'str'

直し方は、このガイド全体でたった 1 つの最も重要な習慣です:まずテキストをバイトに変え、願望の代わりにエンコーディングを意図的に選んでください:

import base64
print(base64.b64encode("été".encode("utf-8")))
# b'w6l0w6k='
print(base64.b64encode("été".encode("utf-16")))
# b'//7pAHQA6QA='

同じ文字でも、バイト列は 2 通り、Base64 の出力も 2 通りです。エンコーディングの選択は詳細ではなく判断です。UTF-8 は、ネットワーク、データベース、API をまたぐものすべてにデフォルトです。UTF-16 は Windows API と話をするときに現れ、先頭に、エンコードしたくなかったかもしれない BOM を持ってきました。utf-16-le を使ったり、lstrip("\ufeff") で削ったりして落とせます。Latin-1 はまだ古いヨーロッパのファイルに隠れていて、そこでは 1 文字がちょうど 1 バイトなので、この問題自体が生じません。押さえておくべきメンタルモデル:エンコーダーはあなたのテキストを見ません。見るのは常にビットだけです。バイトが壁を越えた瞬間、文字コードの質問は閉じます - だからこそ、デコード側は後になって、その文字コードが誰の所有物だったかを問わなければならないのです。

base64url: 2 つの文字を替え、パディングを落とす

標準アルファベットには、URL とファイルシステムが嫌う 2 つの文字が隠れています。+ 記号はどのフォームデコーダーでも黙ってスペースとして読まれ、/ 記号はパスの区切り文字なので、クエリ文字列やファイル名にある標準アルファベットのペイロードは刻々と音を立てる爆弾です。RFC 4648 の 5 節はこの修正を定めています:+ が - に、/ が _ になり、データ長が文脈から分かるときはパディングを落とす変形で、RFC はそれを base64url と呼ぶべきで、単に「base64」ではいけないと強く言っています。JSON Web Token、OAuth トークン、API のカーソルパラメータで出会いますが、つまりはモダンな Web の大部分です。

Python には専用の関数と、最初のセクションの altchars ノブの両方が同梱されていて、出力は同一です:

import base64
data = b"\xfb\xff\xfe"
print(base64.b64encode(data))
# b'+//+'
print(base64.urlsafe_b64encode(data))
# b'-__-'
print(base64.b64encode(data, altchars=b"-_"))
# b'-__-'

トークンやクエリ文字列では、たいていパディングもなくなります。末尾の = はパーセントエンコードが必要になる上、いくつかのミドルボックスがそれを壊すからです:

import base64
padded = base64.urlsafe_b64encode(b"fooba")
print(padded)
# b'Zm9vYmE='
print(padded.rstrip(b"="))
# b'Zm9vYmE'

剥がして送り、受信側は剰余のトリック "=" * (-len(s) % 4) でパッドを付け戻します。長さが要求する数のパッドをちょうど生みます。経験則:データが URL、ファイル名、JWT に住むなら、urlsafe 変種を使ってパッドを落としてください。メールのボディやテキストファイルに住むなら、パディング付きの標準アルファベットが普通です。

読者が行を求めるとき:MIME と 76 文字ルール

b64encode の終わりなき 1 行は、JSON フィールド、ヘッダー、URL に完璧ですが、メールには意見があります。MIME 標準である RFC 2045 は、Base64 の出力を 76 文字以内の行に分割することを要求し、Python のレガシーツールはまさにそれを作るために作られました。Python 3.1 で追加された encodebytes が、バイトオブジェクトのために折り返しをやってくれます:

import base64
wrapped = base64.encodebytes(b"x" * 100)
for line in wrapped.splitlines():
  print(len(line), line[:12])
# 76 eHh4eHh4eHh4
# 60 eHh4eHh4eHh4

仕組みはちょっと可愛いです。モジュールは 57 バイトのチャンクでエンコードします。定数 MAXBINSIZE です。57 バイトがちょうど 76 文字になるからです。モダンな CPython では、折り返された各行はプレーンな LF で終わります。RFC 2045 は CRLF を求めていましたが、Python の LF 出力は、Python 自身のものも含めてエコシステムのすべてのデコーダーに受け入れられます。レガシーのファイル間関数 encode は、同じ折り返しを 1 つのファイルハンドルからもう 1 つのファイルハンドルへ直接行います。メモリに 2 回抱えたくない大きなファイルのための、きちんとしたツールです。

さて、どのツールをいつ使うか、要するに:JSON フィールド、URL、ヘッダー、データベースのカラムに入るものには b64encode;メールのボディと PEM 風のアーマーには encodebytes;大きなファイルをストリーミングしていて、折り返しをタダで得たいときはレガシーの encode。間違った方を選ぶのは古典的なバグです。JSON フィールドの中に改行が 1 つ混入するだけで、向こう側の厳格なデコーダーは例外を送出するからです。

拡張ファミリー

base64 モジュールは、本当は base-N モジュールで、RFC 4648 のファミリー全体に加えて、コンピュータ世界の他の角から来た 2 つの親族を載せています。ほとんどは、同じ「バイトが入ってバイトが出る」契約の 1 行ドロップインです:

関数 アルファベット 出会う場面
b16encode / b16decode 0-9A-F 「Base16」はただの 16 進数;モジュール内でも最速の往復、ハッシュや UUID に最適
b32encode / b32decode A-Z2-7 ライセンスキーとアクティベーションコード;0、O、1、I がなく、音読みされても生き残る
b32hexencode / b32hexdecode 0-9A-V 16 進アルファベットの Base32、Python 3.10 で追加;エンコードデータを辞書順でソート可能に保つ
a85encode / a85decode 印字可能 85 文字 PostScript と PDF から来た ASCII85、Unix の btoa ユティリティの子孫;Python 3.4 からモジュールに
b85encode / b85decode 印字可能 85 文字 git と Mercurial のバイナリ差分が使う Base85 形式;これも Python 3.4 から
z85encode / z85decode 印字可能 85 文字 ZeroMQ の Z85、Python 3.13 で追加;データを 4 バイトずつのグループにフレームする

このどれもの、すでに学んだルールを変えません:バイトが入ってバイトが出て、アルファベットを選んで、向こう側で対応するデコード関数が待っている。実際には、人間が値を読めるべきときに b16 に、値を手打ちや口頭で伝えられるときに b32 に、85 文字の親族には仕様書に言われたときだけに手を伸ばします。それ以外のすべてには、この記事の冒頭の Base64 の組が正しいツールで、モジュールの他のすべてはその上に積まれています。

ページの中の画像:Data URL

Web 上で最も目に見える Base64 が data: URI です:ブラウザが 2 番目のリクエストを発火しないように、メディアを HTML や CSS に直接埋め込むもの。形式は data:、メディアタイプ、base64 という単語、カンマ、エンコードされたバイトの順です。ディスク上のファイルから作るなら 3 行で済みます:

import base64
with open("logo.png", "rb") as handle:
  encoded = base64.b64encode(handle.read()).decode("ascii")
uri = "data:image/png;base64," + encoded
print(uri[:40])
# data:image/png;base64,iVBORw0KGgoAAAAN...

注意が 2 つ、どちらも守るのにコストはかかりません。第一に、ブラウザは data URI を喜んで描画し、ドキュメントの中にメガバイト単位でも喜んで抱えます。数 KB を超えるものは、きちんとしたキャッシュヘッダー付きの普通の画像リクエストが、重要なすべての指標で勝つからです。第二に、コロン後のメディアタイプは約束です。バイトが JPEG なら URI は image/jpeg と書きます。ツールの一部はペアを検証し、レンダラーのいくつかは推測するのを平気で断るからです。.decode("ascii") ステップも装飾ではありません。これがないと、bytes オブジェクトを文字列と連結して TypeError を拾うだけで、型の壁がまた巡ってくるという寸法です。

配っていいトークン:JWT

JSON Web Token はドットで結ばれた 3 つの base64url 部分です:ヘッダー、ペイロード、そして署名。本物のトークンを発行するなら、部分を手作りしないでください。PyJWT(pip install pyjwt)をインストールして、base64url の部分、パディング、署名を 1 回の呼び出しで作らせましょう:

import jwt
# 32 バイト未満のキーは PyJWT の InsecureKeyLengthWarning を受け取ります、デモキーに対する公平な文句です。
token = jwt.encode(
  {"sub": "1234567890", "name": "John Doe"},
  "super-secret-key",
  algorithm="HS256"
)
print(token)
# eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIi...
print(type(token))
# <class 'str'>

内部では、PyJWT はこの記事が説明していることをそのままやっています:JSON に直列化して、urlsafe エンコーダーに通し、パッドを落とす。RFC 7515 の JWS 定義に従ってのことです。テストフィクスチャやデバッグのために、部分を手作りで組み立てる必要が出たら、レシピはどこでも同じ算術です:

import base64
import json
payload = json.dumps({"sub": "1234567890"}).encode("ascii")
part = base64.urlsafe_b64encode(payload).rstrip(b"=")
print(part)
# eyJzdWIiOiAiMTIzNDU2Nzg5MCJ9

信頼の方向性について 1 つ注意:トークンを作るのは簡単な半分です。受信側は、クレームを 1 つでも信頼する前に署名を検証しなければなりません。PyJWT 2.x は、明示的な algorithms リストなしにはトークンをデコードしません。これは機能です。「どのアルゴリズムでも OK」というミスは、これまで書かれてきた認証コードの中で最も高価な行の 1 つだからです。

HTTP: Basic 認証と WebSocket ハンドシェイク

HTTP で 2 つの瞬間が Base64 の上に成り立っています。最初の 1 つは、プロトコルの中で最も古い認証スキームです:Basic 認証(RFC 7617)。クライアントが user:pass を Base64 エンコードして、Basic という単語の後ろに送ります:

import base64
credentials = base64.b64encode(b"jane:pa:ss").decode("ascii")
header = "Basic " + credentials
print(header)
# Basic amFuZTpwYTpzcw==

requests がすでにスタックに入っているなら、auth=("jane", "pa:ss") でこのヘッダーを代わりに作ってくれます。エンコーディングの詳細をコードの外に置けるので、使う価値があります。ついでに、何が起きているかについて正直になりましょう:RFC 7617 は、このスキームは「ユーザー認証の安全な方法ではなく、平文で送信されるエンティティをいかなる意味でも保護しない」とぶっきらぼうに言っています。トラフィックを見る誰でも 1 行のコードで認証情報を復元できるので、これはセキュリティの境界ではなく、TLS 保護された接続のための便利機能です。

2 つ目の瞬間は WebSocket ハンドシェイク(RFC 6455)で、サーバーは、クライアントのランダムキーにマジックな GUID をくっつけた SHA-1 ハッシュの Base64 で答えることで、キーを読んだことを証明します:

import base64
import hashlib
key = "dGhlIHNhbXBsZSBub25jZQ=="
magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
accept = base64.b64encode(
  hashlib.sha1((key + magic).encode("ascii")).digest()
).decode("ascii")
print(accept)
# s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

出力は、RFC 本体の実演例そのものの値です。ゼロから実装をチェックするのになかなか良い方法です。本番では websockets ライブラリが両端でこのステップをやってくれます。手作りするのは、自分の理解を証明するための小さなテストサーバーを書いているときだけです。

メール:最初の顧客

Base64 が 1993 年に標準化されたのは 1 つの仕事のためで、その仕事はメールです:RFC 2045 の Content-Transfer-Encoding: base64 によって、テキストのみの世界である SMTP でバイナリを生き残らせること。Python の email パッケージは、あなた自身が Base64 の 1 行も書かなくても、メッセージを組み、エンコーディングを選び、ボディを標準的な行長で折り返します:

import email.mime.multipart
import email.mime.application
msg = email.mime.multipart.MIMEMultipart()
msg["Subject"] = "binary payload"
part = email.mime.application.MIMEApplication(
  b"\x00\x01\x02", _subtype="octet-stream"
)
msg.attach(part)
text = msg.as_string()
print(text)
# ...
# Content-Transfer-Encoding: base64
#
# AAEC
# --...

MIMEApplication の部分が面白いところです:バイトを正しい 76 文字行に折り返し、transfer-encoding ヘッダーを押印します。これこそ、フレームワークが適用している、以前見た encodebytes の挙動そのものです。メッセージ全体ではなく素の断片を組み立てているなら、email.encoders.encode_base64(obj) がメッセージオブジェクトに対して 1 回のエンコード兼折り返しを直接やってくれます。そしてメッセージが向こう側に着くと、物語のデコード側、get_payload(decode=True) からヘッダーのデコードまで、は関連するデコード記事で扱われています。

鍵と証明書のための PEM アーマー

PEM ファイル - -----BEGIN ...----- で始まる証明書、秘密鍵、CRL - は Base64 の周りのアーマーにすぎません:ラベル行、折り返された Base64、終わりのラベル。アーマーは簡単に見抜けます。ボディは、すでに出会った折り返された出力そのままだからです:

import base64
der = b"\x30\x03\x02\x01\x05"   # 説明用の小さな DER ブロック
body = base64.encodebytes(der).decode("ascii")
armor = ("-----BEGIN CERTIFICATE-----\n"
         + body
         + "-----END CERTIFICATE-----")
print(armor)
# -----BEGIN CERTIFICATE-----
# MAMCAQU=
# -----END CERTIFICATE-----

ラベル行 2 つを剥がして、残りをくっつけると、b64decode が DER バイトを返してくれます。本番ではこれをほぼ手作業でやりません:cryptography パッケージ(pip install cryptography)が public_bytes でアーマーを生成し、load_pem_x509_certificate や仲間たちが解析し、内部で Base64 ステップをやってくれます。手作業の経路が価値を発揮するのは、生の DER バイトがすでに手元にあり(データベースのカラム、設定ファイル、プロトコルからのバッファ)、目の前の仕様書が「PEM にしてください」と言っている、まさにその瞬間です。

ファイルを届ける:アップロード、ダウンロード、.b64 の慣習

インターネットで最も古いユースケースは、テキストしか運ばないチャネルを越えなければならないバイナリファイルです:改行を壊す FTP、アップロードを拒否するフォーム、バイナリを食むチャットウィンドウ。レシピは読み、エンコード、送り、向こう側でデコードさせる。その中で面白い半分は、中央の 2 ステップです:

import base64
with open("photo.png", "rb") as src:
  data = src.read()
wrapped = base64.encodebytes(data)
with open("photo.b64", "wb") as dst:
  dst.write(wrapped)
print(len(wrapped), "bytes on disk for", len(data), "in the photo")
# 元より約 3 分の 1 大きい

注意が 2 つ。.b64 拡張子はコミュニティの慣習であって標準ではないので、受信側もその慣習を知っていなければなりません - それが、JSON API がたいていペイロードを "image_base64" のような名前付きフィールドに包んで、ドキュメントにそう書いておく理由です。そして encodebytes の折り返された 76 文字行は、ディスク上のファイルの選択形式です。メールクライアントから PDF リーダーまで、人間が持つすべてのテキストツールを通じてきれいにコピー&ペーストできるからです。逆方向、つまりそのようなファイルをバイトに戻す読み取りは、関連するデコード記事の 1 呼び出しです。ここではあなたはただの送信側で、送信側の仕事は一貫することです。

ストレージの問題:設定ファイル、環境変数、データベース

開発者は Base64 を、テキストしか受け入れない場所に置くのが好きです:.env ファイル、.ini の設定、TEXT カラム。エンコーディングのステップは自明で、最も一般的な形は Base64 に入った JSON です:

import base64
import json
config = {"api_user": "svc-bot", "api_pass": "hunter2-not-really"}
packed = base64.b64encode(
  json.dumps(config).encode("utf-8")
).decode("ascii")
print(packed)
# eyJhcGlfdXNlciI6ICJzdmMtYm90IiwgImFwaV9wYXNzIjogImh1bnRlcjItbm90LXJlYWxseSJ9

そして警告です。この記事全体で最も高価な誤解が住んでいる場所だからです。Base64 は、通用するほどの隠蔽でも、暗号化でもありません。RFC 4648 の 12 節は、RFC としてできる限り平たく言います:ベースエンコーディングは「パスワードのように、それ自体で簡単に識別できる情報を視覚的に隠すだけで、計算上の秘匿性を一切提供しない」。Base64 のシークレットが入った .env ファイルは、それを一瞥する人間からあなたを守るだけで、それを読む人間からは守ってくれません。base64 -d の 1 コマンド後、「シークレット」はプレーンテキストで相手のターミナルに座っています。データが本当に機密なら、まず暗号化してください - cryptography パッケージはまさにこのために Fernet を同梱しています - そして、ストレージがテキストを要求するなら、そのとき初めて暗号文を Base64 にしてください。

100 万バイト後:ビッグデータとチャンク化

b64encode は C の速さの関数です - 一般的なラップトップなら、1 メガバイトを約 1 ミリ秒で処理します - ただし、それはストリーミング関数ではありません。標準ライブラリにはどこにも update と finish のペアがないので、メモリに抱えたい以上の大きさをエンコードするには、境界の算術を自分でやることです。入力 3 バイトが出力 4 文字を作るので、チャンク境界は 3 バイトの継ぎ目に載らなければなりません:

import base64
def encode_chunks(chunks):
  out = []
  leftover = b""
  for chunk in chunks:
    buffer = leftover + chunk
    whole = len(buffer) // 3 * 3
    if whole:
      out.append(base64.b64encode(buffer[:whole]))
    leftover = buffer[whole:]
  if leftover:
    out.append(base64.b64encode(leftover))
  return b"".join(out)
with open("video.mp4", "rb") as handle:
  encoded = encode_chunks(iter(lambda: handle.read(65536), b""))

出力は、ファイル全体を 1 回の呼び出しでエンコードした場合とバイト単位で同一です。3 バイトの継ぎ目が、グループ分けが壊れうる唯一の場所だからです。パディングはちょうど 1 回だけ、最後のチャンクに現れます。向こう側の厳格なデコーダーが期待しているのはこれです。iter(lambda: handle.read(65536), b"") の 1 行は、ファイルを固定サイズで読む標準的な言い回しで、leftover 変数がアルゴリズム全体です。デコード側は 3 バイトではなく 4 文字の継ぎ目を持たせるので、2 つの記事は算術をそれぞれに分担し、繰り返しません。

エンコーダーが間違える場所

エンコード側はデコード側より罠が少ないです。文字を生み出す側は、失敗しうる場所が少ないからです。それでも、これらは毎週現れ、どれも早めに認識すれば 2 分で直ります:

  • エンコーダーに文字列を与えた。 型の壁セクションの TypeError。ソースのところで .encode("utf-8") で直してください。そして打つ前に、本当に意味している文字コードは何なのか考えてください。
  • 出力がバイトだということを忘れた。 b64encode はバイトを返します。URL や JSON フィールドに入る str を得るには、.decode("ascii") ステップがレシピの一部であって、後付けの発想ではありません。
  • URL 安全スワップを手作りした。 str.replace("+", "-").replace("/", "_") は動きますが、urlsafe_b64encode が 1 呼び出しのところ、2 文字分のメンテナンス負債です。もっと悪く、片手落ちのスワップ、プラスは直してスラッシュを忘れたもの、はどの仕様にも合わないアルファベットを生みます。
  • URL にパッドを残した。 クエリ文字列の末尾の = は、あるツールではパーセントエンコードされ、別のツールでは剥がされ、受信側のパディング算術が最も紛らわしい形で壊れます。剥がしてください。長さがデコーダーに必要なすべてを伝えます。
  • 望まれないところで折り返した。 encodebytes の改行はメールと PEM では正しく、JSON フィールドや URL では毒です。改行が 1 つ混入するだけで、向こう側の厳格なデコーダーは、あなたのフォーマットの問題としてではなく、あなたのデータの問題として例外を送出します。
  • 二重エンコード。 データは上流ですでに Base64 でした - 他の API からプレエンコードされた状態で到着したフィールド、.b64 処理を 2 回受けたファイル - で、2 回目の試行は、最初のエンコードに戻ってデコードできる文字列を生みます。往復は 1 回、マジックバイトを確認して、止めます。
  • シークレットを Base64 に信頼した。 ストレージセクションの警告を、本当に金がかかるので繰り返します:ファイルを読む誰かが脅威モデルに含まれるなら、必要なのは暗号であり、アルファベットではありません。

実際に読める変更履歴

モジュールの年齢は、革命ではなく、静かで日付付きの改善に出ています。簡潔な版、エンコーダーの視点から、部品が着いた順に:

バージョン 何が起きたか
Python 2.4(2004) Barry Warsaw による RFC 3548 の完全サポートが同梱:b16、b32、b64 の各ファミリー、そして今日使われている standard_* と urlsafe_* 変種
Python 3.1(2009) encodebytes が到着し encodestring が非推奨に。古いチュートリアルはいまだにつまずく名前変更
Python 3.4(2014) すべてのエンコーダーがどのバイト風オブジェクトも受け入れ、a85encode と b85encode がモジュールに合流
Python 3.6(2016) binascii.b2a_base64 が newline スイッチを習得。b64encode が終わりなき 1 行を維持できるのはそのため
Python 3.9(2020) レガシーな encodestring と decodestring の名前がようやく削除
Python 3.10(2021) b32hexencode と b32hexdecode、ソート可能な 16 進アルファベットの兄弟
Python 3.13(2024) z85encode と z85decode、ZeroMQ のアルファベットがファミリーに合流
Python 3.14(2025) 標準ライブラリ全体でインポートが速く(base64 も含む)、b16decode は最大 6 倍速。検証は正規表現ではなく bytes.translate で走るようになったため

一本の筋が見たければ:このモジュールは 1995 年に仕事を C レベルの binascii モジュールに委託するために書き直され、その委託は今日でも真です。最初のバイト時代の変化、Python 3 開発中の 2007 年にすべてをどこでもバイトで使うようにしたコミットが、この記事の型の壁の出どころで、それが、モダンなエンコーダーがバイトを受け取りバイトを返す理由であり、それ以外はすべて、その 1 つの契約を包んだラッパーにすぎません。

モジュールが教えてくれないこと

真面目な仕事は終わったので、ここからは帳簿のエンコード側にある小さな喜びたちです:

  • ドキュメント自身の例は 10 年以上、同じデモを回し続けています:b'data to be encoded' が入って、b'ZGF0YSB0byBiZSBlbmNvZGVk' が出てくる。知っているかどうかに関係なく、あなたはこのペアにすでに会っています。
  • b64encode の下の C 関数は、末尾の改行を「礼儀上の改行を追加する」というコメント付きで付け加えます。ソース 1 行に、文化まるごと。
  • 単語 password は cGFzc3dvcmQ= にエンコードされます。これが、ログファイルの Base64 がスキャナにはシークレットのように見える一方、読み手にとっては 1 コマンドでシークレットになりうる理由です。
  • b64encode は決して折り返しません。一度たりとも。1 ギガバイトの入力は 1.3 ギガバイトの 1 行を生み、関数は瞬きもしません。行が欲しかったなら、encodebytes を頼む必要があったのです。
  • モジュールの ドクストリング はまだ 2003 年版仕様の RFC 3548 名を掲げています。RFC 4648 が 2006 年に引き継ぎましたが、ドクストリング はただ気づかなかっただけです。
  • Python 2 には型の壁がまったくなかった:b64encode は str を喜んで受け取り、それを返していた。2007 年のバイト大刷新がそれを終わらせ、「なぜ私のエンコードがクラッシュするんだ」スレッドのほとんどが、今も古い Python 2 チュートリアルを指しています。
  • z85encode、ファミリーで最も新しいメンバー(Python 3.13)は、最も細かいです:ZeroMQ はデータを 4 バイトずつのグループにフレームするので、仕様がエンコードされた出力を 5 文字の倍数と要求します - そしてドキュメントはパディングをあなたに押し付けます:入力は 4 バイトの倍数で到着しなければなりません(エンコーダーが代わってパディングしてくれることはありません。3 バイトの入力は、どの ZeroMQ 同調者も受け入れない 4 文字のフレームを生みます)。

そこで、エンコーダーの哲学を 3 つの規則に。まずバイトを決め、エンコーディングを 2 番目に。型の壁は、Python の Base64 バグの多くが生まれる場所だからです。アルファベットはデータのためにではなくチャネルのために選びなさい:メールとファイルにはパッド付きの標準、URL とトークンにはパッドなしの base64url。そして絶対に、キーボードで第三の変種を即興で作り出さないこと。さらに、出力をその読者が期待する形に保ちなさい:JSON とヘッダーには 1 行、MIME と PEM には 76 文字行。向こう側のデコーダーが、それをもってあなたを責めるからです。

その文字たちが向こう側に着くと、本当の楽しさが始まります:足りないパッド、黙ったままの破棄、Base64 とはいえないペイロード、そして 2 つの気分をナビゲートしなければならないデコーダー。そのすべては、このページの下の関連する Base64 デコード記事で詳しく扱われています。2 つのガイドは組で読むと、よく読めます。良いエンコードを。

最終更新: 2026-10-09

関連記事: Python での Base64 デコード:完全ガイド