PEP 572 - Assignment Expressions вводит новый оператор :=.
Что он делает? Для чего он нужен?
Ответы
Ответ 1
Примеры из существующего (не специально придуманного) кода (grep-нул по диску), к которому можно PEP 572: The Walrus Operator применить:
копирование файлов (и аналогичный код для сокетов и других объектов, из которых можно данные принимать пока не пусто):
# copy the rest
buf = inputfile.read(bufsize)
while buf:
outputfile.write(buf)
buf = inputfile.read(bufsize)
с PEP-572 можно заменить на::
# copy the rest
while buf := inputfile.read(bufsize):
outputfile.write(buf)
что, конечно, и сейчас можно записать как:
# copy the rest
shutil.copyfileobj(inputfile, outputfile, bufsize)
копирование, где shutil.copyfileobj() нельзя напрямую применить (см. Get an audio file with HTTP GET and then play it in python 3. TTS in python 3?):
while True:
data = wavfile.readframes(4096)
if not data:
break
output_file.write(data)
с PEP-572 можно заменить на:
while data := wavfile.readframes(4096):
output_file.write(data)
иногда это пишут через iter() c двумя аргументами (см. Floating point to 16 bit Twos Complement Binary, Python):
output_file.writelines(iter(lambda: wavfile.readframes(4096), b''))
ветвление с регулярными выражениями, к примеру, код из Python 3 get song name from internet radio stream:
m = re.search(r"StreamTitle='([^']*)';", metadata)
if m:
title = m.group(1)
if title:
break # found title
можно заменить на:
if m := re.search(r"StreamTitle='([^']*)';", metadata) and title := m.group(1):
break # found title
списковое включение (listcomp), где какое-то выражение несколько раз используется
К примеру, чтобы напечатать публичные неспециальные свойства объекта obj (атрибуты-не методы) как словарь, созданный dictcomp:
pprint({name: attr
for name in dir(obj) if not name.startswith("__")
for attr in [getattr(obj, name)] if not callable(attr)})
здесь DRY реализуется с помощью: for attr in [getattr(obj, name)] идиомы (добавляется лишний вложенный цикл по списку из одного элемента). C PEP-572 это можно переписать как:
pprint({name: attr
for name in dir(obj)
if not name.startswith("__") and not callable(attr := getattr(obj, name))})
Конечно, особенно в тех случаях когда целое выражение не нужно, можно явный цик
использовать вместо dictcomp.
Ещё пример listcomp (см. Base RLE encode python):
def rle_groupby(text):
return ''.join([char if count == 1 else str(count) + char
for char, same in groupby(text)
for count in [sum(1 for _ in same)]])
здесь та же DRY идиома используется со списком из одного элемента. C PEP-572 эт
можно переписать как:
def rle_groupby(text):
return ''.join([char if (count := sum(1 for _ in same)) == 1 else str(count) + char
for char, same in groupby(text)])
Примеры существующего кода и улучшенных вариантов из самой PEP-572.
Q: Почему нельзя использовать обычный оператор =, как в C#?
A: Чтобы не было путаницы с == как в Си между if (x == y) и if (x = y), которые кардинально разные вещи делают.
Ответ 2
Он не нужен - это так называемый синтаксический сахар, который позволяет писать код более компактно и более понятно.
Вот пример без синтаксического сахара:
if len(string) > 100:
print(len(string)) # дбажды вычисляется len(string)
То же самое:
if (length := len(string)) > 100:
print(length)
Другой пример:
age = input("Ваш возраст: ")
if age > 18: # age должен быть введен перед if
print(age)
может выть
if (age := input("Ваш возраст: ")) > 18:
print(age)
Примечание: Программисты на C/C++ это знают и используют с первых версий этих языков. В Питоне это будет возможно от версии 3.8.
Комментариев нет:
Отправить комментарий