Both ternaries ("if expressions") and comprehensions ("for expressions") are allowed inside f-strings. However, they must be part of expressions that evaluate to strings. For example, key: value is a dict pair, and f"{key}: {value}" is required to produce a string.
>>> dct = {'a': 1, 'b': 2}
>>> newline = "\n" # \escapes are not allowed inside f-strings
>>> print(f'{newline.join(f"{key}: {value}" for key, value in dct.items())}')
a: 1
b: 2
Note that if the entire f-string is a single format expression, it is simpler to just evaluate the expression directly.
>>> print("\n".join(f"{key}: {value}" for key, value in dct.items())))
a: 1
b: 2
Expressions inside format strings still follow their regular semantics. For example, a ternary may test whether an existing name is true. It will fail if the name is not defined.
>>> c, name = "Hello", ""
>>> f'{c} {name if name else "unknown"}'
'Hello unknown'
>>> del name
>>> f'{c} {name if name else "unknown"}'
NameError: name 'name' is not defined
Answer from user5349916 on Stack OverflowWhile you have a loop, you also have a return inside the loop. On the first iteration of the list this return will be hit and execution of the function will stop there, returning only value on that line — which is a string — rather than the list intended.
You either need to add a list to the function to use as an accumulator before returning —
def names_function(lst):
names = []
for name in lst:
names.append(f"{name['first']} {name['last']}")
return names
Or to use a list comprehension
def names_function(lst):
return [f"{name['first']} {name['last']}" for name in lst]
names_function(names)
Both will output
['John Smith', 'Jessie Snow']
You could also replace the return with a yield to turn this into a generator. To get all the values you would need to iterate the generator (or call list on it)
def names_function(lst):
for name in lst:
yield f"{name['first']} {name['last']}"
list(names_function(names))
Which gives the same result
['John Smith', 'Jessie Snow']
if you wantto get all names:
def names_function(lst):
ret=""
for name in lst:
ret += f"{name['first']} {name['last']}\n"
return ret
or
def names_function(lst):
return [f"{name['first']} {name['last']}" for name in lst]
if you want to create a generator object:
def names_function(lst):
return (f"{name['first']} {name['last']}" for name in lst)
The looping construct you're using is a generator expression. To write one as a stand-alone expression, you need to add parentheses around it:
genexp = (f"{s}" for s in ["bar"])
If the generator expression is the only argument to a function, you don't need double parentheses (but you do if there are other separate arguments). Contrast:
s = sum(i % 2 for i in some_sequence) # count of odd elements, no extra parentheses needed
vs:
print(*(i for i in some_sequence if i % 2), sep=",") # print odds, parens are needed this time
There's nothing special about f-string used in the generator expression in your code, any expression works the same way.
These are examples of generator expressions and don't necessarily have anything specific to f-strings or which functions you use with them.
e.g.
>>> x = [1, 2, 3, 4]
>>> sum(i%2==0 for i in x)
2
The example counts the number of even integers in the list.
You can read more about them here: https://dbader.org/blog/python-generator-expressions