辞書内包表記で返す値を関数から取得したい

投稿者: Anonymous

辞書内包表記で記載すると可読性が高いと思い、その方法を探しています。
代案としては下記に記載した通り、関数でTupleを返しdict()を使用する事で実現ができております。

正直、「辞書の内包表記はPythonの構文で定義されているため、関数で返すという事はできない。」という結論になるのではないかと思っております。
もしそうであれば、その旨回答して頂けると助かります
※ドキュメントなどは見つからなかったので提示して頂けると更に嬉しいです
※代案についても他にやり方があれば是非教えてください

詳細は下記に記載します

やりたい事

このようなforで書いたコードを

l = ['a', 'b']
def f(s):
  # 実際にはそれなりにコストがかかる処理でKeyとValueを作成する
  k = s * 2
  v = s * 3
  return k, v
d = {}
for s in l:
  k, v = f(s)
  d[k] = v
print(d) # {'aa': 'aaa', 'bb': 'bbb'}

以下のようなイメージで内包表記で書きたい

l = ['a', 'b']
def f(s):
  # 実際にはそれなりにコストがかかる処理でKeyとValueを作成する
  k = s * 2
  v = s * 3
  # ※ここでどのように返せばよいかを知りたい
  return k:v # イメージです。(構文エラーになります)

d = {f(s) for s in l}
print(d) # {'aa': 'aaa', 'bb': 'bbb'}

※Keyの重複に対する考慮は不要です。

代案

一旦リスト内包表記でList[Tuple]とした上で、dictに変換する

l = ['a', 'b']
def f(s):
  # 実際にはそれなりにコストがかかる処理でKeyとValueを作成する
  k = s * 2
  v = s * 3
  return k, v

d = dict([f(s) for s in l])
print(d) # {'aa': 'aaa', 'bb': 'bbb'}

解決

f(s) の戻り値をタプルにした上でジェネレーター式にすれば高速に書けそうです。

d = dict(f(s) for s in l)

これならリストへの変換もはさみません。

追記:
今こんな感じで比較してみたんですけどあんまり差ないですね……。

>>> def f(x, n):
...   y = [x for x in 'xyzw' * 100]
...   return (x+str(n), x+random.choice(y))
... 
>>> timeit.timeit('x = dict([f(x, n) for n, x in enumerate('abcdef'*10000)])', globals=locals(),number=100)
41.55919947102666
>>> timeit.timeit('x = dict(f(x, n) for n, x in enumerate('abcdef'*10000))', globals=locals(),number=100)
40.46618250303436
>>> 

リスト内包が最適化されてるのと、dict が組み込み関数なので処理が特別なのかもしれません。なのであんま気にしなくてよいのかも。

回答者: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *