Как повторно использовать выражение в выражении понимания? - PullRequest
0 голосов
/ 21 января 2020

Представьте себе теоретический фрагмент:

# just for this example: `bad_structure` contains a list of dicts with different keys
# for the same semantic
bad_structure = [{'path': '/dir/one'}, {'subdir': '/dir/two'}]

# i want to turn this into
# { '/dir/one': some_func('/dir/one'),
#   '/dir/two': some_func('/dir/two')}

result = {}
for e in bad_structure:
  # calculate a value which we will need more than once (here the key)
  p = next(k for k in ('path', 'subdir') if k in e)
  result[p] = some_func(p)

Я хочу сейчас превратить это в понимание слова, и мой первый подход выглядит так:

bad_structure = [{'path': '/dir/one'}, {'path': '/dir/two'}]
result = {next(k for k in ('path', 'subdir') if k in e): 
          some_func(next(k for k in ('path', 'subdir') if k in e))
          for e in bad_structure}

, который содержит «расчет» дважды, что некрасиво, подвержено ошибкам и медленно. Я хотел бы переписать его в s.th. как

result = {p: some_func(p) 
          for p = next(k for k in ('path', 'subdir') if k in e)
          for e in bad_structure}

, который недействителен Python код, конечно ..

Возможно ли что-то подобное в Python?

Для пояснения: я не не заботится о синтаксисе понимания, но повторное использование вычисления без отдельного объявления переменной (что невозможно в закрытых выражениях)

Ответы [ 2 ]

2 голосов
/ 21 января 2020

Вы можете использовать промежуточное понимание для привязки к имени:

result = {
    p: some_func(p)
    # bind intermediate result to p
    for p in (  # nested comprehension to produce intermediate result
        next(k for k in ('path', 'subdir') if k in e)
        for e in bad_structure
    )
 }

Вместо непосредственного сопоставления с двумя отдельными выражениями, оно сначала сопоставляется с общим выражением, которое сопоставляется , а затем до двух отдельных выражений.

Вы можете передавать и переименовывать произвольное количество значений. Создайте кортеж во внутреннем понимании и распакуйте его с несколькими именами во внешнем понимании.

result = {
    p: some_func(e, p)
    for e, p in (
        (e, next(iter(e)))
        for e in bad_structure
    )
 }
2 голосов
/ 21 января 2020

Да! Python 3.8 вводит «Оператор присваивания» :=, который позволяет определять переменную в локальной области видимости одного выражения (например, понимания). В вашем примере вы должны сделать следующее:

result = {(p := next(k for k in ('path', 'subdir') if k in e)): some_func(p) 
          for e in bad_structure}

Отказ от ответственности: это не будет работать ни в одной версии python до 3.8.

...