Python3で、bytes型の文字列にstr型の文字列を埋め込むため、%演算子 + %a を使う

Python3では、文字列表現として

  • str型
  • bytes型

の2つの型があります。

通常はstr型を使うのですが、データ通信などではbytes型を使ったりします。

 
両者は別モノなので、

$ python
Python 3.7.1 (default, Dec 19 2018, 21:58:12) 
[Clang 10.0.0 (clang-1000.11.45.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 'shinano gold' == 'shinano gold'
True
>>> b'shinano gold' == b'shinano gold'
True
>>> 'shinano gold' == b'shinano gold'
False

となります。

 
そんな中、bytes型の文字列にstr型の文字列を埋め込みたいことがあったため、調べたことをメモします。

 
目次

 

環境

 

bytes型では、f-stringsが使えない (PEP-0498より)

Python3.6からはf-stringsを使うことで埋め込みが楽になりましたが、bytes型には使えません。

 
試しに実行してみると、syntaxエラーになりました。

>>> ringo = 'shinano gold'
>>> fb'I love {ringo}'
  File "<stdin>", line 1
    fb'I love {ringo}'
                     ^
SyntaxError: invalid syntax

 

bytes型では .format() が使えない (PEP-0460がobsolete)

PEP-0460がobsoleteのため、bytes型には .format() がありません。
PEP 460 -- Add binary interpolation and formatting | Python.org

 
試しに実行してみると、AttributeErrorになりました。

>>> ringo = 'shinano gold'
>>> b'I love {}'.format(ringo)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'bytes' object has no attribute 'format'

 

%演算子で変換型 %a を使う (Python 3.5〜、PEP-0461)

他の方法を探したところ、Python 3.5より % 演算子%a を使うことにより、埋め込めるようになりました。

 
試しに実行してみます。

>>> b'I love %a' % 'shinano gold'
b"I love 'shinano gold'"

' が含まれるものの、埋め込みできました。

 
' が不要な場合は、replace します。

# ワンライナーの場合
>>> (b'I love %a' % 'shinano gold').replace(b"'", b"")
b'I love shinano gold'

# 変数を使う場合
>>> message = b'I love %a' % 'shinano gold'
>>> message.replace(b"'", b"")
b'I love shinano gold'

 
なお、 %r も使えますが、上記の公式ドキュメントページには

'r' は 'a' の別名です。Python 2/3 の両方を対象としたコードでのみ使用すべきです。

と記載されています。

 

bytes型にbytes型を埋め込む時は、 %演算子 + %b を使う

>>> b'I love %b' % b'shinano gold'
b'I love shinano gold'

 
こちらも、 %s が使えますが、

's' は 'b' の別名です。Python 2/3 の両方を対象としたコードでのみ使用すべきです。

とのことです。