Python实践提升-数值与字符串
现代人的生活离不开各种数字。人的身高是数字,年龄是数字,银行卡里的余额也是数字。大家同样离不开的还有文字。网络上的文章、路边的指示牌,以及你正在阅读的这本书,都是由文字构成的。
我们离不开数字和文字,正如同编程语言离不开“数值”与“字符串”。两者几乎是所有编程语言里最基本的数据类型,也是我们通过代码连接现实世界的基础。
对于这两种基础类型,Python 展现了它一贯的简单易用的特点。拿整型(integer)来说,在 Python 里使用整型,你不需要了解“有符号”“无符号”“32 位”“64 位”这些令人头疼的概念。不论多大的数字都能直接用,不必担心任何溢出问题:
#无符号 64 位整型的最大值(unsigned int64)
>>> 2 ** 64 - 1
18446744073709551615
#直接乘上 10000 也没问题,永不溢出!
>>> 18446744073709551615 * 10000
184467440737095516150000
和数字一样,Python 里的字符串(string)也很容易上手 1。它直接兼容所有的 Unicode 字符,处理起中文来非常方便:
1准确来说,是 Python 3 版本后的字符串容易上手。要处理好 Python 2 及之前版本中的字符串还是有些难度的。
>>> s = 'Hello, 中文'
>>> type(s)
<class 'str'>
#打印中文
>>> print(s)
Hello, 中文
除了上面的字符串类型(str),有时我们还需要同字节串类型(bytes)打交道。在本章的基础知识板块,我会简单介绍二者的区别,以及如何在它们之间做转换。
接下来,我们就从这两种最基础的数据类型开始,踏上探索 Python 对象世界的旅程吧!
2.1 基础知识
本节将介绍与数值和字符串有关的基础知识,内容涵盖浮点数的精度问题、字符串与字节串的区别,等等。
2.1.1 数值基础
在 Python 中,一共存在三种内置数值类型:整型(int)、浮点型(float)和复数类型(complex)。创建这三类数值很简单,代码如下所示:
#定义一个整型
>>> score = 100
#定义一个浮点型
>>> temp = 37.2
#定义一个复数
>>> com = 1+2j
在大多数情况下,我们只需要用到前两种类型:int 与 float。二者之间可以通过各自的内置方法进行转换:
#将浮点数转换为整型
>>> int(temp)
37
#将整型转换为浮点型
>>> float(score)
100.0
在定义数值字面量时,如果数字特别长,可以通过插入 _ 分隔符来让它变得更易读:
#以"千"为单位分隔数字
>>> i = 1_000_000
>>> i + 10
1000010
正如本章开篇所说,Python 里的数值类型十分让人省心,你大可随心所欲地使用,一般不会碰到什么奇怪的问题。不过,浮点数精度问题是个例外。
浮点数精度问题
如果你在 Python 命令行里输入 0.1 + 0.2,你会看到这样的“奇景”:
>>> 0.1 + 0.2
0.30000000000000004
一个简单的小数计算,为何会产生这么奇怪的结果?这其实是一个由浮点数精度导致的经典问题。
计算机是一个二进制的世界,它能表示的所有数字,都是通过 0 和 1 两个数模拟而来的(比如二进制的 110 代表十进制的 6)。这套模拟机制在表示整数时,尚能勉强应对,一旦我们需要小于 1 的浮点数时,计算机就做不到绝对的精准了。
但是,不提供浮点数肯定是不行的。为此,计算机只好“尽力而为”:取一个固定精度来近似表示小数——Python 使用的是“双精度”(double precision)2。这个精度限制就是 0.1 + 0.2 的最终结果多出来 0.000…4 的原因。
2具体来说,是符合 IEEE-754 规范的双精度,它使用 53 个比特的精度来表达十进制浮点数。
为了解决这个问题,Python 提供了一个内置模块:decimal。假如你的程序需要精确的浮点数计算,请考虑使用 decimal.Decimal 对象来替代普通浮点数,它在做四则运算时不会损失任何精度:
>>> from decimal import Decimal
#注意:这里的 '0.1' 和 '0.2' 必须是字符串
>>> Decimal('0.1') + Decimal('0.2')
Decimal('0.3')
在使用 Decimal 的过程中,大家需要注意:必须使用字符串来表示数字。如果你提供的是普通浮点数而非字符串,在转换为 Decimal 对象前就会损失精度,掉进所谓的“浮点数陷阱”:
>>> Decimal(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
如果你想了解更多浮点数相关的内容,可查看 Python 官方文档中的“15. Floating Point Arithmetic: Issues and Limitations”,其中的介绍非常详细。
2.1.2 布尔值其实也是数字
布尔(bool)类型是 Python 里用来表示“真假”的数据类型。你肯定知道它只有两个可选值:True 和 False。不过,你可能不知道的是:布尔类型其实是整型的子类型,在绝大多数情况下,True 和 False 这两个布尔值可以直接当作 1 和 0 来使用。
就像这样:
>>> int(True), int(False)
(1, 0)
>>> True + 1
2
#把 False 当除数的效果和 0 一样
>>> 1 / False
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
布尔值的这个特点,最常用来简化统计总数操作。
假设有一个包含整数的列表,我需要计算列表里一共有多少个偶数。正常来说,我得写一个循环加分支结构才能完成统计:
numbers = [1, 2, 4, 5, 7]
count = 0
for i in numbers:
if i % 2 == 0:
count += 1
print(count)
#输出:2
但假如利用“布尔值可作为整型使用”的特性,一个简单的表达式就能完成同样的事情:
count = sum(i % 2 == 0 for i in numbers) ➊
❶ 此处的表达式 i % 2 == 0 会返回一个布尔值结果,该结果随后会被当成数字 0 或 1 由 sum() 函数累加求和
2.1.3 字符串常用操作
本节介绍一些与字符串有关的常用操作。
把字符串当序列来操作
字符串是一种序列类型,这意味着你可以对它进行遍历、切片等操作,就像访问一个列表对象一样:
>>> s = 'Hello, world!'
>>> for c in s: ➊
... print(c)
...
H
...
d
!
>>> s[1:3] ➋
'el'
❶ 遍历一个字符串,将会逐个返回每个字符
❷ 对字符串进行切片
假如你想反转一个字符串,可以使用切片操作或者 reversed 内置方法:
>>> s[::-1] ➊
'!dlrow ,olleH'
>>> ''.join(reversed(s)) ➋
'!dlrow ,olleH'
❶ 切片最后一个字段使用 -1,表示从后往前反序
❷ reversed 会返回一个可迭代对象,通过字符串的 .join 方法可以将它转换为字符串
字符串格式化
Python 语言有一个设计理念:“任何问题应有一种且最好只有一种显而易见的解决方法。”3如果把这句话放到字符串格式化领域,似乎就有点儿难以自圆其说了。
在当前的主流 Python 版本中,至少有三种主要的字符串格式化方式。
(1) C 语言风格的基于百分号 % 的格式化语句:‘Hello, %s’ % ‘World’。
(2) 新式字符串格式化(str.format)方式(Python 2.6 新增):“Hello, {}”.format (‘World’)。
(3) f-string 字符串字面量格式化表达式(Python 3.6 新增):name = ‘World’; f’Hello, {name}'。
第一种字符串格式化方式历史最为悠久,但现在已经很少使用。相比之下,后两种方式正变得越来越流行。从个人体验来说,f-string 格式化方式用起来最方便,是我的首选。和其他两种方式比起来,使用 f-string 的代码多数情况下更简洁、更直观。
举个例子:
username, score = 'andy', 100
#1. C 语言风格格式化
print('Welcome %s, your score is %d' % (username, score))
#2. str.format
print('Welcome {}, your score is {:d}'.format(username, score))
#3. f-string,最短最直观
print(f'Welcome {
username}, your score is {
score:d}')
#输出:
#Welcome andy, your score is 100

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



