Python学习笔记--数值与字符串

发布时间:2024年01月23日

本文内容摘自朱雷老师著《Python工匠》一书内容,为学习笔记摘录。

一、数值基础

在Python中,一共存在3种内置数值类型:整型(int)、浮点型(float)、复数类型(complex)。创建如下:

# 定义一个整型
score = 100
# 定义一个浮点型
temp = 37.2
# 定义一个复数
com = 3+4j

# 创建一个复数  
z = complex(3, 4)  # 创建一个复数,实部为3,虚部为4  
print(z)  # 输出:3+4j

在大多数情况下,主要使用前两种类型:int和float。二者之间可以通过个值得内置方法进行转换:

>>> i = 1_00_000_0000
>>> i
1000000000
>>> j = 2_345_5678
>>> j
23455678
>>>?

在定义数字字面量时,如果数字特别长,可以通过插入下划线 _ 分隔符来让它变得更易读,如:

# 以“千”为单位分割数字

>>> i = 1_000_000_000
>>> i
1000000000

# 其实,可以随意位数间隔,比如
>>> j = 2_345_5678
>>> j
23455678
>>>?


一个问题:浮点数精度

如果在Python命令行输入0.1 + 0.2 ,你会看到这样的奇景:

>>> 0.1+0.2
0.30000000000000004
>>>?
解决这样的问题,可以使用Python内置模块decimal。如果程序需要精确的浮点数计算,可以考虑使用decimal.Decimal对象来替代普通浮点数,它在做四则运算时候不会损失任何精度:

>>> from decimal import Decimal

# 注意:这里的“0.01”和“1.01”必须是字符串
>>> Decimal("0.01") + Decimal("1.01")
Decimal('1.02')
>>>?
?

布尔值其实也是数字

布尔(bool)类型是Python里用来表示“真假”的数据类型,包括两个可选值:True和False。布尔值其实是整型的子类型,在绝大多数情况下,True和False可以当做1和0来使用。就像如下这样:

>>> int(True),int(False)
(1, 0)
>>> True + 1
2
>>> False +1
1
>>> 1 /True
1.0

# 把False当做除数,和0一样会抛出异常
>>> 1 /False
Traceback (most recent call last):
? File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>>?

利用“布尔值可作为整型使用”的特性,用一个简单的表达式实现统计一个包含整数列表中的偶数的数量:

>>> numbers = [1,2,3,4,5,6,7,8,9,10,11,12]
>>> count = sum(num % 2 == 0 for num in numbers)
>>> count
6
>>>?

特殊数字:“无穷大、无穷小”

Python中float("inf")和float("-inf")分别代表数学世界中的正负无穷大。

float("-inf")? < 任意数值 < float("inf")

比如有一个包含用户名和年龄的字典,我们需要把里面的用户名按照年龄升序排序,没有提供年龄的放在最后面。下面代码使用float("inf"),代码可以这么写:

def sort_users_inf(users):

    def key_func(username):
        age = users[username]
        # 当年龄为空时,返回正无穷大作为key,因此会被排到最后
        return age if age is not None else float("inf")
    
    return sorted(users.keys(),key=key_func)

users = {"liuzx":19,"jenny":13,"jack":None,"liuyf":48}

print(sort_users_inf(users))   # 输出:['jenny', 'liuzx', 'liuyf', 'jack']

二、字符串的格式化

当前主流Python版本中,有3种主要的字符串格式化方式。

(1)C语言风格的基于百分号%的格式化语句:‘Hello, %s’? %? 'World'.

(2)新式字符串格式化(str.format)方式:"Hello ,{}".format("World")

(3)f-string字符串字面量格式化表达式(Python3.6新增):如下:

>>> name = "World"
>>> welcome_text = f"Hello,{name}"
>>> welcome_text
'Hello,World'
>>>

后两种方式越来越流行被采用,f-string格式化方式用起来最为方便,作者建议首选。

str.format 与f-string共享同一种复杂的“字符串格式化微语言”。通过这种微语言,可以方便地对字符串进行二次加工,然后输出。比如:

# 将username靠右对齐,左侧补齐空格到一共20个字符

# 下面两种方式将输出同样的内容

>>> username = "liuyf"
>>> print('{:>20}'.format(username))
? ? ? ? ? ? ? ?liuyf
>>> print(f'{username:>20}')
? ? ? ? ? ? ? ?liuyf
>>>?

一个应用案例:

字符串与字节串

(1)字符串:普通的字符串,也称为文本(text),是给人看的,对应Python中的字符串(str)类型。str使用Unicode标准,可以通过.encode()方法编码为字节串。

(2)字节串:有时也称为“二进制字符串”(binary string),是给计算机看的,对应Python中的字节串(bytes)类型。bytes一定包含某种真正的字符串编码格式(默认为UTF-8),可通过.decode()方法解码为字符串。

>>> str_obj = 'Hello,火星'
>>> str_obj
'Hello,火星'
>>> type(str_obj)
<class 'str'>
>>> bin_str = str_obj.encode('UTF-8')
>>> bin_str
b'Hello\xef\xbc\x8c\xe7\x81\xab\xe6\x98\x9f'
>>> type(bin_str)
<class 'bytes'>
>>>

bytes和str是两种不同的数据类型,即使有时看上去“一样”,但是做比较时永不相等:

>>> "Hello" == b"Hello"
False
>>>

另外,不能使用bytes来调用任何内置方法,反之亦然:

>>> "Hello".split("e")
['H', 'llo']
>>> "Hello".split(b"e")
Traceback (most recent call last):
? File "<stdin>", line 1, in <module>
TypeError: must be str or None, not bytes
>>>?

在程序中,尽量保证总是操作普通字符串,而非字节串。必须操作处理字节串的场景一般有两种:

(1)程序从文件或其它外部存储读取字节串内容,将其解码为字符串,然后在内部使用。

(2)程序完成处理,要把字符串写入文件或者其它外部存储,将其编码为字节串,然后继续执行其它操作。

小知识:普通字符串采用的是文本格式,没法直接存放于外部存储,一定要将其编码为字节串——也就是“二进制字符串”。比如一些文本编辑器编辑文本,我们看到是文本(普通字符串),当编辑器把文本作为文件保存到硬盘等存储器时,会进行编码,把文本及格式转换为字节串,才能保存到存储设备中。

改善代码的可读性案例

Python中没有真正的常量类型,一般把大写字母全局变量当做“常量”来用。比如把积分数定义为常量:

# 用户每日登录奖励积分数量

DAILY_POINTS_REWARDS = 100

# VIP用户每日登录,额外再奖励积分20

VIP_EXTRA_POINTS = 20

除了常量之外,Python3.4开始引入了专门用于表示枚举类型的内置模块,在程序中可以定义枚举类型(enum.Enum)作为常量:

from enum import Enum

# 在定义枚举类型时,如果同时继承一些基础类型,比如int,str
# 枚举类型就能同时充当该基础类型使用,必须下面代码,使用UserType就可以充当int使用

DIALY_POLINTS_REWARDS = 100
VIP_EXTRA_POLINTS = 20

class UserType(int,Enum):
    # VIP 用户
    VIP = 3
    # 封禁的用户(黑名单用户)
    BANNED = 13

def add_daily_points(user):
    """用户每天完成第一次登录后,为其增加积分
    """
    # 用户为封禁用户
    if user.type == UserType.BANNED:
        return
    
    # 用户为VIP用户
    if user.type == UserType.VIP:
        user.points += DIALY_POLINTS_REWARDS + VIP_EXTRA_POLINTS
        return
    
    # 普通用户
    user.points = DIALY_POLINTS_REWARDS
    return

使用常量和枚举变量类型的好处:

(1)代码更易读:所有人都不需要记忆某个数字代表什么。

(2)代码更健壮:降低输错数字或者字母产生bug的可能性。

改善超长字符串的可读性

为了保证代码的可读性,单行代码的长度不易过长,比如PEP8规范建议每行字符数不超过79,大部分人遵循不超过119个字符。遇到超长的字符串怎么办?

除了使用斜杠\和加号+将长字符串拆分为几段,还有一种更简单的方法,就是拿括号将长字符串包起来,之后就可以随意折行了。

s = ("This is the first line of a long string,"
     "this is the second line."
     )
print(s)  # 输出:"This is the first line of a long string,this is the second line."

如果字符串出现在函数参数等位置,可以省略一层括号,下面语句输出和上面是一样的。

print("This is the first line of a long string,"
      "this is the second line."
      )

文章来源:https://blog.csdn.net/2303_79232676/article/details/135748142
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。