Что делает звезда (звездочка) в струнной?

В документе python 2.4.3. Отформатированные строковые литералы, кажется возможным написать звезду, за которой следует выражение в f-строке {}, но я не могу найти, как это использовать.

Что это и как я могу это использовать? Это где-то задокументировано?

Чтобы быть точным, это касается "*" or_expr части следующего BNF.

f_string          ::=  (literal_char | "{{" | "}}" | replacement_field)*
replacement_field ::=  "{" f_expression ["!" conversion] [":" format_spec] "}"
f_expression      ::=  (conditional_expression | "*" or_expr)
                         ("," conditional_expression | "," "*" or_expr)* [","]
                       | yield_expression

Я попробовал это в REPL, но это вызывает ошибку.

>>> l = [1, 2, 3]
>>> f"{l}"
'[1, 2, 3]'
>>> f"{*l}"
  File "<stdin>", line 1
SyntaxError: can't use starred expression here

Ответы

Ответ 1

Существует две альтернативы для f_expression: разделенный запятыми список or_expression s, перед которыми необязательно or_expression звездочки, или одиночное yield_expression. Обратите внимание, что yield_expression не позволяет использовать звездочку.

Я предполагаю, что намерение состояло в том, что альтернатива списка через запятую выбирается только тогда, когда есть хотя бы одна запятая, но на самом деле грамматика этого не говорит. Я чувствую, что оператор повторения в конце должен был быть + вместо *.

Так что f"{*1}" будет синтаксической ошибкой, потому что есть звездочка, но без запятой. f"{*1,*2}" синтаксически допустимо, но ошибка типа, потому что 1 и 2 не повторяемы. f"{*[1], *[2]}" является действительным и действует так же, как f"{1,2}". Таким образом, звездочка разрешена, потому что она действует как оператор splat в кортежах, которые могут быть записаны без скобок в f-выражениях.

Обратите внимание, что использование or_expr в качестве операнда для * не означает, что там должен использоваться побитовый оператор или - он просто означает, что побитовый оператор или является первым оператором в иерархии предшествования, который будет разрешен в качестве операнда для * Так что это просто установка приоритета префикса * сравнению с другими выражениями. Я полагаю, что or_expression последовательно используется как операнд для префикса * везде в грамматике (то есть везде, где за префиксом * следует выражение, а не имя параметра).

Ответ 2

Насколько я знаю, вы можете использовать в контексте функции внутри f строки.

Вот рабочий пример:

def do_print(*l):
    return l


print(f"{do_print(*(1, 2, 3))}")

Это распечатывает:

(1, 2, 3)

тогда как, если вы попробуете:

print(f"{do_print((1, 2, 3))}")

вы получите этот вывод:

((1, 2, 3),)

Одиночная звезда * распаковывает tupe в позиционные аргументы функции и может использоваться внутри вызова внутри строки f.

Другой пример:

def sum(a, b):
    return a + b

print(f"{sum(*(1, 2))}")

Ответ 3

Ясно, что "*" не означает, что вы можете использовать оператор * или, по крайней мере, это не то, что они намеревались сказать. Если вам разрешено использовать помеченное выражение или помеченный элемент напрямую, это было бы явно упомянуто с одной из следующих нотаций.

expression_list    ::=  expression ("," expression)* [","]
starred_list       ::=  starred_item ("," starred_item)* [","]
starred_expression ::=  expression | (starred_item ",")* [starred_item]
starred_item       ::=  expression | "*" or_expr

Как видите, "*" or_expr является частью грамматики starred_item которая не имеет никакого смысла, потому что вы можете использовать любую двоичную f_string операцию в f_string. Я думаю, что это скорее ошибка документации, чем ошибка в коде.

Отказ от ответственности:

Даже если or_expr является идентификатором для expr который из-за ссылок на ссылки в doc очень запутан и явно ошибочен, он все равно является ошибкой в документации, поскольку, во-первых, он не соответствует поведению исходного кода, а во-вторых, зачем использовать *expr вместо правильных помеченных обозначений выражений с меньшей неопределенностью.

Я отправил вопрос здесь https://bugs.python.org/msg341187. Я надеюсь, что это может помочь выяснить проблему для нас.

Ответ 4

Посмотрите здесь: https://realpython.com/python-f-strings/. У них есть большой список новых способов, которыми Python поддерживает форматирование строк. Честно говоря, никогда в жизни не видел такого рода звездочек. Может быть, это что-то новое. Надеюсь, поможет.

Ответ 5

Я не думаю, что * f-string должна использоваться для списка, более вероятно, что она будет использоваться для умножения

In [81]: f"{5*2}"                                                                                                                                             
Out[81]: '10'

Ответ 6

Я не хочу искажать ваш вопрос здесь, но у меня есть то, что я считаю наиболее разумным ответом.

Если вы посмотрите на этот вопрос, им будет интересно, почему они не могут отформатировать строку, используя синтаксис % как показано ниже.

>>> l = [1, 2, 3]
>>> "%d" % *l
  File "<stdin>", line 1
SyntaxError: can't use starred expression here

По сути, я собираю, что слишком много ценностей для распаковки, но не так, как вы думаете. Видите, в f-строке {...} ожидается одно значение, и, передав коллекцию и пытаясь распаковать ее одновременно (даже если коллекция имеет только одно значение, я попытался ради здравого смысла) Python кричит на вас потому что вы будете передавать несколько значений чему-то ожидающему только одно.

То, что у меня есть для вас, это альтернативный метод. Это не так красиво, как использование звездочки *, но результат такой же, как и ожидалось.

>>> l = [1, 2, 3]
>>> f"{', '.join(map(str, l))}"
'1, 2, 3'

Печать упрощает работу, но все должно выполняться вручную при форматировании строки