Python наконец получил выражения присваивания в версии 3.8. Но обсуждение включало:
Во время разработки этого PEP многие люди (как сторонники, так и критики) имели тенденцию сосредотачиваться на игрушечных примерах, с одной стороны, и на слишком сложных примерах, с другой. .
Игрушечные примеры опасны двояко: они часто слишком абстрактны, чтобы заставить кого-нибудь go «ох, это убедительно», и их легко опровергнуть, сказав: «Я бы никогда не стал так писать».
Итак, вот реальный пример: я пишу парсер DSL, я хочу, чтобы он работал на Python версиях, отличных от последней, и я не могу понять Pythoni c способ сделать это.
Итак, если вы «никогда не будете писать это (нижний образец кода) таким образом», как do вы напишите оператор case в Python 3,7 без использования бесконечных уровней вложенности?
import re
doc = """
123 45 6789
red sky at night
abc42
[foo, bar+, $)&%(@]
ContentType: image/jpeg
"""
pat1 = r'^\s*(\w+)\s*$'
pat2 = r'^\s*(\d+(?:\s+\d+)*)\s*$'
pat3 = r'^\s*(\w+):\s*(\w+\/\w+)\s*$'
pat4 = r'^\s*\[([^]]+)\]\s*$'
# Python 3.8+
for line in doc.splitlines():
if m := re.match(pat1, line):
print(f'Type 1: |{m.group(1)}|')
elif m := re.match(pat2, line):
print(f'Type 2: |{m.group(1)}|')
elif m := re.match(pat3, line):
print(f'Type 3: |{m.group(1)}|{m.group(2)}|')
elif m := re.match(pat4, line):
print(f'Type 4: |{m.group(1)}|')
elif line:
print(f'Unknown Format: |{line}|')
print('=============')
# Python 3.x <3.8
for line in doc.splitlines():
m = re.match(pat1, line)
if m:
print(f'Type 1: |{m.group(1)}|')
else:
m = re.match(pat2, line)
if m:
print(f'Type 2: |{m.group(1)}|')
else:
m = re.match(pat3, line)
if m:
print(f'Type 3: |{m.group(1)}|{m.group(2)}|')
else:
m = re.match(pat4, line)
if m:
print(f'Type 4: |{m.group(1)}|')
elif line:
print(f'Unknown Format: |{line}|')
Вывод не имеет значения, это игрушечный пример для иллюстрации реальной проблемы. Но для записи, работающей под Python 3.7, генерируется синтаксическая ошибка.
Запуск под Python 3.8 дает:
Type 2: |123 45 6789|
Unknown Format: | red sky at night|
Type 1: |abc42|
Type 4: |foo, bar+, $)&%(@|
Type 3: |ContentType|image/jpeg|
=============
Type 2: |123 45 6789|
Unknown Format: | red sky at night|
Type 1: |abc42|
Type 4: |foo, bar+, $)&%(@|
Type 3: |ContentType|image/jpeg|
EDIT:
Подход Хелвуда самый простой. Легко понять с первого взгляда, больше, чем перебирать шаблоны или отправлять.
Это все еще намного уродливее, чем версия Python 3.8. Я понятия не имею, почему кто-то будет против выражений присваивания или почему Python потребовалось так много времени, чтобы их получить.
# Python 3.7
def process_line(ln):
m = re.match(pat1, ln)
if m:
print(f'Type 1: |{m.group(1)}|')
return
m = re.match(pat2, ln)
if m:
print(f'Type 2: |{m.group(1)}|')
return
m = re.match(pat3, ln)
if m:
print(f'Type 3: |{m.group(1)}|{m.group(2)}|')
return
m = re.match(pat4, ln)
if m:
print(f'Type 4: |{m.group(1)}|')
return
print(f'Unknown Format: |{ln}|')
for line in doc.splitlines():
if line:
process_line(line)
EDIT (orial) # 2:
Теперь я знаю, почему Python потребовалось так много времени, чтобы реализовать такую простую и полезную идею: PEP 572 Controversy . Отвращение к всему фиаско привело к тому, что создатель Python навсегда ушел в отставку, и это предостерегающий рассказ об опасностях дизайна комитета. Позор тем, кто несет ответственность за эту потерю.