一、简介
string模块定义了一种新字符串类型Template,它简化了特定的字符串置换操作。
何谓“简化”?我们可以先想一下我们之前比较常用的有关字符串的“置换”操作有哪些:一种是利用%操作符实现,另外一种是格式化字符串format实现。那么,相比于这两种方法,string.Template究竟简化在何处呢?
那我们就以下面的代码为例简单说明一下string.Template的用法与上述两种方式的区别:
# -*- coding: utf-8 -*- # -*- Author: WangHW -*- import string values = {'var':3.3333333} #1 t1 = string.Template(""" Variable : $var Escape : $$ Variable in text: ${var}iable """) print('TEMPLATE:',t1.substitute(values)) print('############################') #2 s = """ Variable : %(var)s Escape : %% Variable in text: %(var)siable """ print('INTERPOLATION:',s % values) print('############################') #3 s1 = """ Variable {var} Escape : {{}} Variable in text: {var}iable """ print('FORMAT:',s1.format(**values))
结果如下:
上面的代码分别利用string.Template方法、%操作符以及format方法进行了字符串的置换操作。这里我们可以看出string.Template是利用$符号进行“关联”,用substitute方法取值的。
这里直接给出结论:利用string.Template方法是不需要考虑参数的数据类型的!这是string.Template方法与后面两种方法最重要的不同之处。string.Template方法直接将参数转换为字符串格式,然后将转换后的字符串直接插入结果中去。没有可用的格式化选项供我们选择,例如,对于一个浮点数(如上述例子所示)来讲,我们没办法控制代表这个浮点数数值的位数。
二、safe_substitute方法
上例中我们利用substitute取值。大家肯定会问了:如果$关联的字符串在前面定义的values中不存在怎么办?难道会报错吗?
答案是肯定的!为了避免上述问题的产生我们利用safe_substitute方法取值,当然可以跟原生的substitute方法对比一下:
# -*- coding: utf-8 -*- # -*- Author: WangHW -*- import string values = {'var':'foo'} t = string.Template('$var is here but $missing is not provided') try: print('substitute() :',t.substitute(values)) except KeyError as err: print('ERROR:',str(err)) print('safe_substitute():',t.safe_substitute(values))
结果如下:
大家可以看到:values中并没有代表key的字符串'missing',而我们在Template中却试图利用$missing取其对应的值。因此substitute方法会报错,而safe_substitute方法可以巧妙的“避免”这个错误,保证程序的流畅性。
三、进阶:模块功能的“修改”
在实际中,大家可能习惯利用%操作符去进行字符串的置换了,那么,如果我们既想利用string.Template方法的便捷性,又想按照自己的意愿与需求定义额外的功能,这就需要我们新定义一个继承自string.Template的类(例如命名为MyTempate),在这里修改其中的某些属性去满足我们的需求。
下面代码中MyTemplate类继承自string.Template,修改了操作符delimiter与id模式idpattern,实现了利用%关联代表key的字符串,然后利用正则表达式使safe_substitute()只能匹配出带下划线的且由a-z组成的字符串:
# -*- coding: utf-8 -*- # -*- Author: WangHW -*- import string class MyTemplate(string.Template): #操作符 delimiter = '%' #id模式 idpattern = '[a-z]+_[a-z]+' if __name__ == '__main__': template_text = ''' Delimiter : %% Replaced : %with_underscore Ignored : %notunderscored ''' d = { 'with_underscore':'replaced', 'notunderscored':'not replaced' } t = MyTemplate(template_text) print('Modified ID pattern:') print(t.safe_substitute(d))
结果如下:
上例中,由于代表key的字符串‘notunderscored’没有下划线,没有匹配到,所以结果中只能得出%notunderscored,不能取到具体的值。
需要注意的是:这种方法在实际中非常常用!在实际中我们需要根据具体的需求灵活的“更改”模块中某个对象的某个属性去实现具体的需求!