为什么在string.format()字典引用中不需要'?

时间:2018-03-15 23:13:20

标签: python python-3.x dictionary string-formatting

my_dic={"Vajk":"vékony","Bibi":'magas'}
my_dic['Bibi']
'magas'

我们可以看到,我们需要'引用关键'Bibi'的值。但是如果想在.format()中使用相同的格式,则会出现此错误:

print("úgy érzem, hogy Bibi nagyon {0['Bibi']}".format(my_dic))
Traceback (most recent call last):

  File "<ipython-input-109-52760dad9136>", line 1, in <module>
    print("úgy érzem, hogy Bibi nagyon {0['Bibi']}".format(my_dic))

KeyError: "'Bibi'"

我必须使用没有'的引用,然后它可以工作。

print("úgy érzem, hogy Bibi nagyon {0[Bibi]}".format(my_dic))
úgy érzem, hogy Bibi nagyon magas

为什么不首先工作,为什么第二个工作?它应该是相反的,首先应该工作,第二个不应该。

2 个答案:

答案 0 :(得分:5)

首先,一些术语:

  • 'Bibi'字符串文字,用于创建字符串值的语法。您的键是字符串,使用字符串文字,您可以指定其中一个键。

    您可以改用变量;将字符串值赋值给变量并使用该变量从字典中获取项目:

    foo = 'Bibi'  # or read this from a file, or from a network connection
    print(my_dic[foo])  # -> magas
    
  • 在字符串格式设置中,{...}替换字段str.format()方法为替换字段提供值。

  • 0[Bidi]替换字段语法中的{...}部分是字段名称。在字段名称中使用[...]时,它是复合字段名称(有多个部分)。 [...]语法通常称为索引。

字段名称中使用的格式有意保持简单,只有Python- 类似。语法被简化以限制它可以用于什么,将功能约束到通常安全使用的东西。

因此,如果使用带有getitem [...]索引语法的复合名称,则将名称视为字符串,但不使用引号来创建字符串。无论如何,您无法传递变量名称,无需在'name'(字符串)和name(变量)之间进行对比。

换句话说,在Python表达式中,my_dic[foo]通过查找变量foo的值来工作,这与使用像my_dic['Bidi']这样的字符串文字不同。但是无法在字段名称中使用变量,在str.format()操作中,使用{0[foo]}永远不会找到变量foo

原始proposal to add the feature将此解释为:

  

与其他一些编程语言不同,您不能在格式字符串中嵌入任意表达式。这是设计 - 您可以使用的表达类型是故意限制的。只支持两个运营商:'。' (getattr)运算符和'[]'(getitem)运算符。允许这些操作符的原因是它们通常在非病理代码中没有副作用。

  

应该注意的是,格式字符串中'getitem'的使用比传统用法更有限。在上面的例子中,字符串'name'实际上是文字字符串'name',而不是名为'name'的变量。解析项密钥的规则非常简单。如果以数字开头,则将其视为数字,否则将其用作字符串。

保持语法简单使模板更安全。来自Security Considerations section

  

除此之外,下一个最好的方法是确保字符串格式没有副作用。由于Python的开放性,不可能保证任何非平凡的操作都具有此属性。这个PEP所做的是将格式字符串中的表达式类型限制为那些可见的副作用很少并且受到Python开发人员文化强烈反对的表达式。

允许{0[foo]}在当前范围内查找变量很容易产生副作用,而将foo视为字符串则意味着您可以肯定地知道它始终是字符串'foo'而不是别的。

如果您使用字符串文字而不是动态值(所以'some {} template'.format(...)而不是some_variable.format(...),并且您使用的是Python 3.6或更高版本,则可以使用{{ 3}}然后,您可以使用完整的Python表达式:

print(f"úgy érzem, hogy Bibi nagyon {my_dic['Bibi']}")

f字符串中,您使用实际的Python表达式而不是字段名称,因此再次使用引号传入字符串文字。因为它们是字符串文字,所以它们会在定义它们的地方进行评估,而作为开发人员,您可以看到哪些局部变量可用,因此您可能知道如何保证其安全。

答案 1 :(得分:2)

  

它应该是相反的,首先应该工作,第二个不应该。

不,它不应该是因为双引号字符串中的'Bibi'是带引号的字符串而不仅仅是Bibi。您可以按照以下方式检查:

In [51]: "'Bibi'" == "Bibi"
Out[51]: False

如果在第一种情况下,密钥为"'Bibi'"那么它就能完美运行:

In [49]: my_dic={"Vajk":"vékony","'Bibi'":'magas'}

In [50]: print("úgy érzem, hogy Bibi nagyon {0['Bibi']}".format(my_dic))
úgy érzem, hogy Bibi nagyon magas

为什么它在第一种情况下不接受"Bibi"并且没有给出预期结果的原因是Python在字典中查找括号之间的所有内容,在这种情况下,你有括号内的"'Bibi'"不是'Bibi'