Python str 1個入りタプルやリストを作る時の罠を踏んだ

まとめ

str 要素 1個入りの tuple, list を作るときは括弧で作ると安全。

t = ('abc',)   # ケツカンマがないと怒られる
l = ['abc']

tuple() や list() のコンストラクタ形式を使うと罠にはまるかも。

経緯

('abc',)
['abc']

↑の結果が欲しくて↓のようにすると、

t = tuple('abc')
l = list('abc')

↓のようになって Why となったわけです。

('a', 'b', 'c')
['a', 'b', 'c']

よくよく考えると、tuple, list のコンストラクタは class tuple([iterable]) , class list([iterable]) で、 Python では str 自体が Iterable なので、

t = tuple('abc')
l = list('abc')

とすると、'abc' が Itarable 扱いされて 1 文字ごとになったタプル/リストが作られたと。

('a', 'b', 'c')
['a', 'b', 'c']


str 単体でも str の Iterable でも受け付けるようなメソッド書くとき

def hoge (arg: Union[str. Iterable[str]]) -> None:

後のコードを共通にするため、単体の時は tuple や list でラップして、というのがよくやる手かと思いますが、↓のようにしてしまうと罠を踏み抜くわけですね。

def hoge (arg: Union[str. Iterable[str]]) -> None:
  if instanceof(arg, str):
    arg = tuple(arg)

  for x in arg:
     # 何かする

こういうラップするときは

  if not instanceof(arg, Iterable):
    arg1 = (arg, )

とするのが安全ぽい