lmiguelvargasf
lmiguelvargasf

Reputation: 70003

Is it possible to reuse an f-string as it is possible with a string and format?

I would like to create an f-string that could be used multiple times as the following code with format:

TEXT_AMOUNT = 'text {amount}'


def f1(beginning):
    return beginning + TEXT_AMOUNT.format(amount=10)


def f2(ending):
    return TEXT_AMOUNT.format(amount=100) + ending

How can I achieve the same functionality with using an f-string? I tried:

TEXT_AMOUNT = f'text {amount}'


def f1(beginning):
    amount = 100
    return beginning + TEXT_AMOUNT


def f2(ending):
    amount = 10
    return TEXT_AMOUNT + ending

However, I get the following error:

NameError: name 'amount' is not defined

Upvotes: 13

Views: 10051

Answers (3)

Vespertilio
Vespertilio

Reputation: 321

You can store it as lambda function:

TEXT_AMOUNT = lambda amount: f'text {amount}'
print(TEXT_AMOUNT(10))

out: 'text 10'

Upvotes: 22

bd2357
bd2357

Reputation: 794

But you can put f-string in a function and reuse it that way

def TEXT_AMOUNT(amount):
    return f'text {amount}'

def f1(beginning):
    return beginning + " " + TEXT_AMOUNT(amount=10)

def f2(ending):
    return TEXT_AMOUNT(amount=100) + " " + ending

print(f1("first"))
print(f2("last"))

first text 10

text 100 last

Upvotes: 10

abarnert
abarnert

Reputation: 366133

You can't.

An f-string isn't a kind of string, it's a kind of string literal, which is evaluated immediately. You can't store an f-string in a variable to be evaluated later, or accept one from a user, etc.1 This is the only reason that they're safe.

So, what if you do want to use a format multiple times (or one taken from a user, etc.)? You use str.format.

Occasionally, you need to capture all of the locals and globals the same way an f-string does, but to do it explicitly. Because this is a rare case (and potentially a security hole), it's intentionally a bit ugly:

TEXT_AMOUNT = 'text {amount}'

def f1(beginning):
    amount = 100
    return beginning + TEXT_AMOUNT.format(**locals(), **globals())

This makes you think about what you're writing—you don't really want globals here, right? So leave it off. And it also signals the reader—if you're pulling in locals, they'll want to see that the string really is a constant in your source that isn't doing anything dangerous.


1. Well, you could use an f-string inside a string that you pass to eval… but that's a terrible idea.

Upvotes: 14

Related Questions