前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何使用Python 进行字串格式化

如何使用Python 进行字串格式化

作者头像
会呼吸的Coder
发布2020-02-17 16:51:06
9470
发布2020-02-17 16:51:06
举报
文章被收录于专栏:会呼吸的Coder会呼吸的Coder

前言

在开发应用程序时我们往往会需要把变量进行字符串格式化,也就是说把字符串中的变量替换成变量值。事实上,在Python 中有许多方式可以进行,其中最常见的有四种方式(有三种,但Python 字符串格式化方式竟然有四种!):

  1. 旧式字符串格式化
  2. 新式字符串格式化
  3. 字符串插值
  4. 样板字符串

字符串插值是在Python 3.6 之后有支持的方法,若是你的版本是在Python 3.6 之后的话建议可以使用。若是需要让使用者可以输入变量来转换成字符串格式化的话,建议可以使用样板字符串来避免一些数据安全上的问题。

以下就上述提到的四种方法来各自说明其特色和使用方式:

旧式字符串格式化(%)

相对于Python版本之后推荐使用的新式字符串格式化,旧式版本使用%运算子来进行字符串格式化,若是有C语言编写经验的读者或许会觉得的似曾相似(是不是有点像printf?)。使用%格式是告诉Python直译器要在那边替换文字text并使用字符串呈现。这就是所谓的旧式字符串格式化(%s是以字符串输出,%f是以浮点数输出、%d是以十进制整数输出):

代码语言:javascript
复制
text = 'world'
print('hello %s' % text)
# hello world

若是希望把内容转成十六进制的话可以使用:

代码语言:javascript
复制
print('%x' % 23)
# 17

若是有多个变量要替换则使用tuple 传递需要替代的内容值:

代码语言:javascript
复制
代码语言:javascript
复制
print('hello %s %s' % ('world', 'go'))# hello world go

新式字符串格式化(format())

在Python3以后,开始引进新串格式化,也就是使用format()函数来让字符串格式化,其功能和旧式格式化相差无几,但主要是舍去%让字符串格式化使用上可以更加正常、规律,可读性也相对提升。

一般基本用法:

代码语言:javascript
复制
text = 'world'
print('hello {}'.format(text))
# hello world

也可以使用名称来指定变量变换顺序:

代码语言:javascript
复制
name = 'Jack'
text = 'world'

print('hello {name}, hello {text}'.format(name=name, text=text))
# hello Jack, hello world

若是希望把内容转成十六进制的话可以使用format spec在{}新增:x

代码语言:javascript
复制
print('{:x}'.format(23))

字符串插值(Formatted String Literal)

虽然已经有了新式字符串格式化,然而在Python 3.6又新增了格式字符串字面值(Formatted String Literal)此一作法可以把Python运算式嵌入在字符串常数中。 眼尖的读者可能会发现,咦,怎么跟隔壁棚的JavaScript ES6字符串模版有点像呀?

现在我们来看一下一般的使用方式:

代码语言:javascript
复制
text = 'world'
print(f'Hello, {text}')

新的字符串插值语法相当强大的点是,可以在里面嵌入任何Python 的运算式,举例来说,我们想要呈现整数相加:

代码语言:javascript
复制
x = 10
y = 27

print(f'x + y = {x + y}')
# 37

同样,若是希望把内容转成十六进制的话可以使用format spec在{}新增:x

代码语言:javascript
复制
print('{:x}'.format(23))
# 17

读者可能会觉得很字符串插值神奇,但事实上其背后原理是由Python 语法解析器把f-string 字符串插值格式字符串转成一连串的字符串常数和运算式,最后结合成最终的字符串。

代码语言:javascript
复制
def hello(text, name):
    return f'hello {text}, hello {name}'

# 实际上 Python 会把它变成字串常量和变量(过程中有变化)

def hello(text, name):
    return 'hello ' + text + ', hello' + name

样板字符串(Template String)

样板字符串(Template String)机制相对简单,也比较安全。

以下是一般的使用情境,需要从Python 内建模组string 引入:

代码语言:javascript
复制
from string import Template

text = 'world'
t = Template('hello, $text')
t.substitute(text=text)
# hello, world

然而若是希望把内容转成十六进制的话需要自己使用hex 函数自己转换:

代码语言:javascript
复制
from string import Template

number = 23
t = Template('hello, $number')
t.substitute(number=hex(number))
# hello, 0x17

由于其他的字符串格式化功能较为强大,所以反而会造成恶意使用者输入变量替换成字符串时造成不可预期的错误(一般来说使用者的输入都是不可信的,要进行过滤)。

举例来说恶意使用者可能可以通过字符串格式的恶意输入来获取敏感数据(例如:密码、token、金钥等)?;

代码语言:javascript
复制
SECRET_TOKEN = 'my-secret-token'

# Error func
class Error:
    def __init__(self):
        pass

err = Error()
malicious_input = '{error.__init__.__globals__[SECRET_TOKEN]}'
malicious_input.format(error=err)
# my-secret-token

没想到,通过字符串格式的方式竟然可以通过__globals__字典取出我们的SECRET_TOKEN,若是一不留神,很可能机密资料就泄漏出去。此时若是使用Template String则会发生错误,是比较安全的选项:

代码语言:javascript
复制
from string import Template

SECRET_TOKEN = 'my-secret-token'

# Error func
class Error:
    def __init__(self):
        pass

err = Error()
malicious_input = '${error.__init__.__globals__[SECRET_TOKEN]}'
t = Template(malicious_input)
t.substitute(error=err)
# ValueError: Invalid placeholder in string: line 1, col 1

总结

虽然Python 的信仰是能用简单唯一的方式来完成任务,然而字符串格式化却有多种方式,也各有其优缺点,其主要原因或许在于版本不同变迁所致。所以你有可能在公司内部专案不同专案看到使用不同的字符串格式化方式,若是看到同一个专案使用不同字符串格式化方式也不要惊讶。

一般情况我们会根据不同Python 版本和使用情境去使用不同字符串格式化方式,例如:若是使用Python 3.6 之后的话建议可以使用字符串插值,若版本比3.6 旧,则使用新式字符串格式化(format ())。若是需要让使用者可以输入变量来转换成字符串格式化的话,建议可以使用样板字符串来避免一些数据安全上的问题。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 初级程序员 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 旧式字符串格式化(%)
  • 新式字符串格式化(format())
  • 字符串插值(Formatted String Literal)
  • 样板字符串(Template String)
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档