变量
你想创建一个内嵌变量的字符串,变量被它的值所表示的字符串替换掉。
解决方案
Python并没有在字符串中简单替换变量值提供直接的支持,但是通过使用字符的format()方法来解决这个问题,比如:
s='{name} has {n} message'
print(s.format(name='XingXing',n=35)) # ->XingXing has 35 message
或者,如果要被替换的变量能在变量域中找到,那么你可以结合使用format_map()和vars()。就像下面这样:
name='XingXing'
n=35
print(s.format_map(vars())) # ->XingXing has 35 message
vars()还有 一个有意思的特性就是它也适用于对象实例。比如:
class Info:
def __init__(self,name,n):
self.name=name
self.n=n
a=Info('XingXing',35)
print(vars(a)) # ->{'name': 'XingXing', 'n': 35}
print(s.format_map(vars(a))) # ->XingXing has 35 message
format和format_map()的一个缺陷就是他阿门不能很好的处理变量缺失的情况。
print(s.format(name='XingXing'))
输出结果:
Traceback (most recent call last): File "D:/study/workspace/python学习/python3高级/第二章:字符串和文本/2-15字符串中插入变量.py", line 16, in <module> print(s.format(name='XingXing')) KeyError: 'n'
一种避免这种错误的方法是另外定义一个含有__missing__()
方法的字典的对象,就像下面这样:
name='XingXing'
class safesub(dict):
def __missing__(self, key):
return "{"+key+"}" # ->XingXing has {n} message
print(s.format_map(safesub(vars())))
n=35
如果你发现自己的代码中频繁的执行这些步骤,你可以将变量替换步骤用一个工具函数封装起来,就像下面这样写
import sys
def sub(text):
return text.format_map(safesub(sys._getframe(1).f_locals))
name='XingXing'
n=37
print(sub('Hello {name}')) # ->Hello XingXing
print(sub('You have {n} message.')) # ->You have 37 message.
print(sub('Your favorite color is {color}')) # ->Your favorite color is {color}
讨论
多年以来由于python缺乏对变量替换的内置支持而导致了各种不同的解决方案。作为本节中展示的一个可能方案,你可以有时候看到像下面这样的字符串格式:
import string
s=string.Template("$name has $n message.")
print(s.substitute(vars()))# XingXing has 37 message.
format()方法还有一个好处就是你尅获得对字符串格式化的所有支持(对齐,填充,数字格式化等),而这些特性是使用像模板字符串之类的方案不可能获得的。
__missing__()
方法可以让你定义如何处理缺失的值,在SafeSub类中,这个犯法被定义为缺失的值返回一个占位符。你可以发现缺失的值会出现在结果字符串中(在调试的时候可能很有用),而不是产生一个KeyError异常。
sub()函数使用功能sys._getframe(1)
返回调用者的栈帧。可以从中访问属性f_locals来获得局部变量。毫无疑问绝大部分情况下在代码中去直接操作栈帧应该是不推荐的。但是对于像字符串替换工具函数而言它是非常有用的。另外,值得注意的是f_locals是一个复制调用函数的本地变量 的字典。尽管你可以改变f_locals的内容,但是这个修改对于后面的变量访问没有任何影响。所以,虽说访问一个栈帧看上去是很邪恶的,大事对它的任何操作不会覆盖和改变调用者本地变量的值。