为什么 f-strings 在它们引用的变量发生变化时不发生变化?

Why don't f-strings change when variables they reference change?

在最近的 Python 3.6 版本中演奏新的 f 弦时,我注意到以下几点:

  1. 我们创建一个 foo 变量,值为 bar:

    >>> foo = 'bar'
    
  2. 然后,我们声明一个新的变量,就是我们的f-string,格式化需要foo

    >>> baz = f'Hanging on in {foo}'
    
  3. 好的,一切正常,然后我们调用 baz 来检查它的值:

    >>> baz
    'Hanging on in bar'
    
  4. 让我们尝试更改foo的值并再次调用baz

    >>> foo = 'spam'
    >>> baz
    'Hanging on in bar'
    

不应该是动态的吗?为什么会这样?我认为如果 foo 的值发生变化,f 字符串会更新,但这并没有发生。我不明白这是怎么回事。

f-string 在您执行时 已经 求值:

>>> baz = f'Hanging on in {foo}'

具体来说,它查找了名称 foo 的值并将其替换为 'bar',即为其找到的值。 baz 然后包含格式化后的字符串。

f-strings 不是常数;意思是,它们内部没有等待评估 after 的替换字段。 当你执行它们时它们会计算,之后,分配的值是只是一个普通的字符串:

>>> type(f'hanging on in {foo}')
<class 'str'>

参考资料见the section on Formatted String Literals:

[..] While other string literals always have a constant value, formatted strings are really expressions evaluated at run time. [..]

执行表达式(查找替换字段及其后续格式化)后,它们没有什么特别之处,表达式已被评估为字符串并分配给 baz

字符串是不可变的,字符串一旦创建,就不能再更改。

foo 更重要的是 baz 都是字符串。这意味着当您创建它们时,它们会进入内存并且无法再更改。

分配 foo = bar 后,您就创建了该对象并将其分配到内存中的特定位置。 baz 也做了同样的事情。

即使 baz 作为 Format string literal 并不意味着它不再是不可变的,因为:

In [4]: type(baz)
Out[4]: str

通过这样做,baz 被创建为一个对象并作为 Hanging on in bar 分配给您的内存,因此它与 foo 的关系纯粹是在实例化期间。在此期间 baz 寻找对象 foo 并在适当的地方连接它。

创建 foo = 'spam' 后,您 破坏了 foo 的原始分配并在内存中创建了一个新分配。