教会小白写Python(3)——数据类型

66 阅读20分钟

写在前面:许多人,尤其是家里的长辈,谈论起学习,总认为学习是一件轻松的事。却忽略了,对于很多人来说,知识的消化过程非常痛苦。他们常说"失败是成功之母",却不告诉你有些失败只会生出更多的失败;他们说"坚持就是胜利",却不告诉你盲目的坚持只是顽固的另一种说法。真正的学习是一场与自己的搏斗,是对舒适区的背叛,是对已知世界的重新审视。它不是那种让你喝下去就能立刻感到温暖的汤,而是一剂苦口的良药,服下去时痛苦,却能在将来救你一命。 学习这件事,它让你看清痛苦的根源,不是让你逃避这个世界,而是为了在看清它的本质后,依然有能力去改变它、享受它。真正的英雄就应该是这个样子的:体验过世间诸多的残酷,还能保持对生活的热爱;

正文:

Python中,一切皆为对象,上一章我提到过,每个对象都有一个 标识 (内存地址)、一个 类型 和一个 。Python是一种动态类型语言,变量名不需要声明类型,而是在赋值时自动确定类型。例如,当我们执行x = 42时,Python会创建一个整数对象,其值为42,并将变量x绑定到这个对象。

可变型与不可变型

Python的数据类型可以分为两类:可变类型和不可变类型。这里我先提出来,后面还会深入讲解一番。

不可变类型:对象创建后不能修改其内容,包括:

  • 所有数字类型(int, float, complex)
  • 布尔类型(bool)
  • 字符串(str)
  • 元组(tuple)
  • 冻结集合(frozenset)

可变类型:对象创建后可以修改其内容,包括:

  • 列表(list)
  • 字典(dict)
  • 集合(set)

一、Python内置数据类型详解

Python默认内置了以下这些数据类型,分为几大类:

在这里插入图片描述

1. 数值类型(Numeric Types)

整数(int)

Python中的整数拥有无限精度,可以表示任意大小的整数。

# 创建整数
a = 42
b = 0
c = -7
d = 10_000_000  # 可使用下划线增强可读性,
e = 0b1010      # 二进制表示:10(使用0b选择二进制)
f = 0o12        # 八进制表示:10(使用0o选择八进制)
g = 0xA         # 十六进制表示:10(使用0x选择十六进制)

# 常用操作
result = a + b  # 加法
result = a - c  # 减法
result = a * c  # 乘法
result = a / c  # 除法(结果为float)
result = a // c # 整除
result = a % c  # 取余
result = a ** 2 # 幂运算

这里我觉得有必要说明一点,整数可以有二、八、、十、十六进制,但是python默认为十进制。

进制名称Python前缀使用的数字示例等价十进制值
十进制0-9123\
二进制0b 或 0B0-10b111115
八进制0o 或 0O0-70o1715
十六进制0x 或 0X0-9, A、B、C、D、E、F0xF15

浮点数(float)

浮点数由整数部分和小数部分组成

# 创建浮点数
a = 3.14
b = 2.0
c = -0.5
d = 1.23e-4  # 科学计数法:0.000123

# 常用操作
result = a + b  # 加法
result = round(a, 2)  # 四舍五入到2位小数
result = abs(c)       # 绝对值

要注意的是,浮点数计算可能存在精度问题,例如:

print(1.1+2.2) #输出 3.3000000000000003

这是因为,计算机是使用二进制存储的,许多十进制小数无法被精确表示。例如,十进制的 0.1 在二进制中是一个无限循环小数,但计算机只能存储有限位数,会对其进行舍入处理,从而导致误差。

对于需要精确计算的场景,可以使用decimal模块。这个模块提供了基于十进制的高精度浮点数运算,可以避免二进制浮点数的舍入误差。

from decimal import Decimal     #从decimal模块中引入Decimal()方法,如何在python中引用模块会在后面的章节中提到
a = Decimal('0.1')
b = Decimal('0.2')
c = Decimal('0.3')
print(a + b == c)  # 输出 True

对于需要极高精度的场景,可以使用第三方库如mpmath,它支持任意精度的浮点数运算。

复数(complex)

复数由实部和虚部组成,表示为a + bj形式,其中 j 是虚数单位

# 创建复数
a = 3 + 4j
b = complex(2, 3)  # 等同于2 + 3j

# 常用操作
result = a + b     # 复数加法
result = a * b     # 复数乘法
print(a.real)      # 获取实部:3.0
print(a.imag)      # 获取虚部:4.0
print(abs(a))      # 获取模值:5.0
print(a.conjugate())  # 获取共轭复数:3 - 4j

布尔值(bool)

布尔类型只有两个值:TrueFalse。在Python中,布尔值是整数的子类,True对应整数1,False对应整数 0 。所以,布尔值是可以运算的:

# 创建布尔值
a = True
b = False
c = bool(1)      # True
d = bool(0)      # False
e = bool("abc")  # True(非空字符串为True)
f = bool("")     # False(空字符串为False)

# 布尔运算
result = a and b  # 逻辑与
result = a or b   # 逻辑或
result = not a    # 逻辑非

# 布尔值参与数值运算
num = 5 + True    # 结果为6

2. 文本类型(Text Type)

字符串(str)

字符串是不可变的Unicode字符序列,可以用单引号、双引号或三引号定义,这点前面的文章已经提及,这里不再赘述。

# 创建字符串
s1 = 'Hello'
s2 = "World"
s3 = '''This is a
multi-line string'''

3. 序列类型(Sequence Types)

第一节下面的内容在这里只做了解就行,不必深究,后面的文章还会一一提到,到那时会展开来讲。

列表(list)

列表是可变的有序集合,可以包含不同类型的元素

# 创建列表
empty_list = []
numbers = [1, 2, 3, 4, 5]
mixed = [1, "Hello", 3.14, True]
nested = [1, [2, 3], [4, 5]]
generated = list(range(5))  # [0, 1, 2, 3, 4]

# 列表操作
item = numbers[0]           # 索引访问:1
numbers[0] = 10             # 修改元素
sub_list = numbers[1:3]     # 切片操作:[2, 3]
numbers.append(6)           # 添加元素
numbers.insert(1, 1.5)      # 插入元素
numbers.extend([7, 8])      # 扩展列表
numbers.remove(5)           # 移除指定元素
popped = numbers.pop()      # 移除并返回最后一个元素
popped_index = numbers.pop(0)  # 移除并返回指定索引的元素
index = numbers.index(3)    # 查找元素索引
count = numbers.count(2)    # 计算元素出现次数
numbers.sort()              # 排序(原地修改)
numbers.reverse()           # 反转(原地修改)
sorted_nums = sorted(numbers)  # 排序(返回新列表)
length = len(numbers)       # 获取长度

元组(tuple)

元组是不可变的有序集合,与列表类似,但创建后不能修改

# 创建元组
empty_tuple = ()
single_item = (1,)  # 注意:单元素元组需要逗号
numbers = (1, 2, 3, 4, 5)
mixed = (1, "Hello", 3.14)
nested = (1, (2, 3), (4, 5))

# 元组操作
item = numbers[0]       # 索引访问
sub_tuple = numbers[1:3]  # 切片操作:(2, 3)
length = len(numbers)   # 获取长度
count = numbers.count(2)  # 计算元素出现次数
index = numbers.index(3)  # 查找元素索引
contains = 3 in numbers  # 检查是否包含:True

范围(range)

range是一个不可变的序列类型,用于表示一个连续的整数序列

# 创建range对象
r1 = range(5)         # 0, 1, 2, 3, 4   
r2 = range(1, 6)      # 1, 2, 3, 4, 5
r3 = range(0, 10, 2)  # 0, 2, 4, 6, 8
r4 = range(5, 0, -1)  # 5, 4, 3, 2, 1

# range操作
item = r2[2]          # 索引访问r2中的第二个值:3
sub_range = r2[1:3]   # 切片操作:range(2, 4)
length = len(r2)      # 获取r2长度:5
contains = 3 in r2    # 检查r2是否包含3:True

4. 映射类型(Mapping Type)

字典(dict)

字典是可变的键值对集合,键必须是不可变类型(如字符串、数字、元组)

# 创建字典
empty_dict = {}
person = {"name": "Alice", "age": 30, "city": "New York"}
using_dict = dict(name="Bob", age=25)
from_pairs = dict([("name", "Charlie"), ("age", 35)])

# 字典操作
value = person["name"]      # 通过键访问值:'Alice'
person["age"] = 31          # 修改值
person["email"] = "alice@example.com"  # 添加新键值对
removed = person.pop("city")  # 移除键值对并返回值
default_val = person.get("phone", "Not Available")  # 获取值,不存在时返回默认值
keys = person.keys()        # 获取所有键
values = person.values()    # 获取所有值
items = person.items()      # 获取所有键值对
person.update({"phone": "123-456-7890", "age": 32})  # 更新多个键值对
person.clear()              # 清空字典
length = len(person)        # 获取长度
contains = "name" in person  # 检查键是否存在

5. 集合类型(Set Types)

集合(set)

集合是可变的无序集合,元素不重复,元素必须是不可变类型

# 创建集合
empty_set = set()  # 注意:{}创建的是空字典,不是空集合
numbers = {1, 2, 3, 4, 5}
mixed = {1, "Hello", (1, 2)}
from_iterable = set([1, 2, 2, 3, 3, 3])  # {1, 2, 3}

# 集合操作
numbers.add(6)         # 添加元素
numbers.remove(3)      # 移除元素(元素不存在会引发错误)
numbers.discard(10)    # 移除元素(元素不存在不会引发错误)
popped = numbers.pop()  # 移除并返回任意元素
numbers.clear()        # 清空集合

# 集合运算
a = {1, 2, 3}
b = {3, 4, 5}
union = a | b          # 并集:{1, 2, 3, 4, 5}
intersection = a & b   # 交集:{3}
difference = a - b     # 差集:{1, 2}
symmetric_diff = a ^ b  # 对称差集:{1, 2, 4, 5}
subset = {1, 2}.issubset(a)  # 判断是否为子集:True
superset = a.issuperset({1, 2})  # 判断是否为超集:True

冻结集合(frozenset)

frozenset是不可变的集合,创建后不能添加或删除元素

# 创建冻结集合
empty_fset = frozenset()
fset = frozenset([1, 2, 3, 2])  # frozenset({1, 2, 3})

# 集合运算(与set相似,但不支持修改操作)
a = frozenset([1, 2, 3])
b = frozenset([3, 4, 5])
union = a | b          # 并集
intersection = a & b   # 交集
difference = a - b     # 差集
symmetric_diff = a ^ b  # 对称差集

还有很多类型就不一一列举了,将来在实际项目中遇到,可以 one by one 地补充

二、数据类型转换

为什么需要转换数据类型?

我举个例子就能很快明白,为什么需要转换数据类型

name = '张三'
age = 24

# 现在我想要打印一句话:我叫张三,今年24岁
print('我叫'+name+',今年'+age+'岁') # 使用连接符“+”连接字符
# 输出结果:
    print('我叫'+name+',今年'+age+'岁')
          ~~~~~~~~~~~~~~~~~~~~^~~~
TypeError: can only concatenate str (not "int") to str

这里就出现报错,意思是不能使用int来连接str。这时我们就需要将int类型改为str类型,使用str()方法就能实现。

print('我叫'+name+',今年'+str(age)+'岁')
# 输出正确

这个例子里,为了向你展示为什么需要转换数据类型,故意使用了麻烦的连接写法。实际上在 Python 3.6 及以上版本中,只需在字符串前加一个f,然后用大括号{}嵌入变量:

print(f"我叫{name},今年{age}岁")

1. 数值类型之间的转换(整数、浮点数、复数)

整数和浮点数之间的转换是数值转换中最常见的场景。使用int()float()函数可以轻松实现这些转换

# 示例1:基本整数与浮点数转换
int_number = 42
float_number = 3.14159

# 整数转浮点数
float_from_int = float(int_number)
print(f"整数 {int_number} 转换为浮点数: {float_from_int}")  # 输出:42.0

# 浮点数转整数(注意:这会直接截断小数部分,而不是四舍五入)
int_from_float = int(float_number)
print(f"浮点数 {float_number} 转换为整数: {int_from_float}")  # 输出:3

在浮点数转换为整数时,需要注意的是int()函数会直接截断小数部分,而不是进行四舍五入。如果需要四舍五入,可以使用round()函数

# 示例2:使用round()函数进行四舍五入
float_number = 3.7
int_truncated = int(float_number)  # 直接截断
int_rounded = round(float_number)  # 四舍五入

print(f"直接截断:{int_truncated}")  # 输出:3
print(f"四舍五入:{int_rounded}")  # 输出:4

# 复杂一点的例子:保留指定小数位数
pi = 3.14159265359
rounded_pi_2 = round(pi, 2)  # 保留两位小数
print(f"π保留两位小数:{rounded_pi_2}")  # 输出:3.14

使用complex()函数可以创建复数或将其他数值类型转换为复数

# 示例3:创建复数和转换
real_part = 3
imaginary_part = 4

# 创建复数
complex_number = complex(real_part, imaginary_part)
print(f"从整数创建的复数: {complex_number}")  # 输出:(3+4j)

# 从单个数值创建复数(虚部默认为0)
complex_from_float = complex(2.5)
print(f"从浮点数创建的复数: {complex_from_float}")  # 输出:(2.5+0j)

# 从字符串创建复数
complex_from_string = complex("1+2j")
print(f"从字符串创建的复数: {complex_from_string}")  # 输出:(1+2j)

需要注意的是,虽然可以将整数和浮点数转换为复数,但不能直接使用将复数转换为整数或浮点数。如果需要提取复数的实部或虚部,可以使用复数对象的属性,也就是.real.imag

# 示例4:提取复数的实部和虚部
complex_number = 3 + 4j

real_part = complex_number.real
imaginary_part = complex_number.imag

print(f"复数 {complex_number} 的实部是: {real_part}")  # 输出:3.0
print(f"复数 {complex_number} 的虚部是: {imaginary_part}")  # 输出:4.0

2. 字符串与数值类型之间的转换

字符串与数值类型之间的转换是日常编程中非常普遍的操作,尤其是在处理用户输入或数据解析时

字符串转换为数值类型

将字符串转换为数值类型时,需要确保字符串的内容可以表示为对应的数值

# 示例1:基本字符串转数值
str_integer = "123"
str_float = "45.67"

# 字符串转整数
integer_from_str = int(str_integer)
print(f"字符串 '{str_integer}' 转换为整数: {integer_from_str}")  # 输出:123

# 字符串转浮点数
float_from_str = float(str_float)
print(f"字符串 '{str_float}' 转换为浮点数: {float_from_str}")  # 输出:45.67

# 字符串转复数
complex_from_str = complex("3+4j")
print(f"字符串 '3+4j' 转换为复数: {complex_from_str}")  # 输出:(3+4j)

在进行字符串到数值的转换时,如果字符串内容无法转换为目标数值类型,Python会抛出ValueError异常

数值类型转换为字符串

将数值类型转换为字符串可以使用str()函数,这在格式化输出或与字符串拼接时非常有用

# 示例2:数值转字符串
integer_value = 123
float_value = 45.67
complex_value = 3 + 4j

# 转换为字符串
str_from_int = str(integer_value)
str_from_float = str(float_value)
str_from_complex = str(complex_value)

print(f"整数 {integer_value} 转换为字符串: '{str_from_int}'")  # 输出:'123'
print(f"浮点数 {float_value} 转换为字符串: '{str_from_float}'")  # 输出:'45.67'
print(f"复数 {complex_value} 转换为字符串: '{str_from_complex}'")  # 输出:'(3+4j)'

实际上,可以了解一下字符串格式化,它是一种更灵活的方式来将数值融入字符串中,无需显式转换

# 示例3:使用字符串格式化
name = "Python"
version = 3.9
users = 8.2

# 使用f-string进行格式化(Python 3.6+)
message1 = f"{name} {version}{users} 百万用户"
print(message1)  # 输出:Python 3.9 有 8.2 百万用户

# 使用format()方法格式化
message2 = "{} {} 有 {} 百万用户".format(name, version, users)
print(message2)  # 输出:Python 3.9 有 8.2 百万用户

# 控制数值格式
formatted_users = f"{users:.1f}"  # 限制为一位小数
print(f"{name} {version}{formatted_users} 百万用户")  # 输出:Python 3.9 有 8.2 百万用户

3. 布尔值的转换规则

布尔值(True和False)是Python中的基本数据类型,表示逻辑真与假。了解布尔值的转换规则对编写条件语句和逻辑运算至关重要。

其他类型转换为布尔值

在Python中,使用bool()函数可以将其他类型转换为布尔值。转换规则简单而一致:空值或零值转换为False,其他值转换为True

# 示例1:各种类型转换为布尔值
# 数值类型
print(f"bool(0) = {bool(0)}")  # 整数0转换为False
print(f"bool(1) = {bool(1)}")  # 非零整数转换为True
print(f"bool(-3.14) = {bool(-3.14)}")  # 非零浮点数转换为True

# 序列类型
print(f"bool('') = {bool('')}")  # 空字符串转换为False
print(f"bool('Python') = {bool('Python')}")  # 非空字符串转换为True
print(f"bool([]) = {bool([])}")  # 空列表转换为False
print(f"bool([1, 2]) = {bool([1, 2])}")  # 非空列表转换为True
print(f"bool(()) = {bool(())}")  # 空元组转换为False
print(f"bool({}) = {bool({})}")  # 空字典转换为False

# None值
print(f"bool(None) = {bool(None)}")  # None转换为False

有些转换规则在条件表达式和逻辑运算中非常有用,允许我们直接使用各种对象作为条件,而不必显式转换为布尔值。虽然这句话表达起来比较抽象,但是有一点python基础的同学在看到下面的例子时就会恍然大悟。如果你是刚学习的新手,也不必纠结,后面还会反复提到,隐式转换布尔值在程序中非常常见。

# 示例2:在条件表达式中隐式转换为布尔值
numbers = [1, 2, 3]
name = ""

# 检查列表是否为空
if numbers:  # 隐式转换为布尔值
    print("列表不为空")
else:
    print("列表为空")

# 检查字符串是否为空
if name:  # 隐式转换为布尔值
    print(f"用户名: {name}")
else:
    print("未提供用户名")

# 结合逻辑运算符
result = numbers and name  # 短路求值,返回name(空字符串)
print(f"numbers and name = {result}")  # 输出:空字符串

result = numbers or name  # 短路求值,返回numbers(非空列表)
print(f"numbers or name = {result}")  # 输出:[1, 2, 3]

布尔值转换为其他类型

布尔值也可以转换为其他类型,最常见的是转换为整数(True为1,False为0)。

4.集合类型之间的转换(列表、元组、集合、字典)

Python提供了丰富的集合类型,包括列表(list)、元组(tuple)、集合(set)和字典(dict)。这些类型之间的转换是数据处理中的常见操作。在本章节了解即可,后面我们在学习集合类型的时候还会学到。

列表、元组和集合之间的转换

列表、元组和集合具有相似的特性,它们都可以存储一组元素,因此它们之间的转换通常很直接

# 示例1:基本的集合类型转换
original_list = [1, 2, 3, 2, 4, 1]

# 列表转元组
tuple_from_list = tuple(original_list)
print(f"列表转元组: {tuple_from_list}")  # 输出:(1, 2, 3, 2, 4, 1)

# 列表转集合(注意:集合会自动去除重复元素)
set_from_list = set(original_list)
print(f"列表转集合: {set_from_list}")  # 输出:{1, 2, 3, 4}

# 元组转列表
list_from_tuple = list(tuple_from_list)
print(f"元组转列表: {list_from_tuple}")  # 输出:[1, 2, 3, 2, 4, 1]

# 元组转集合
set_from_tuple = set(tuple_from_list)
print(f"元组转集合: {set_from_tuple}")  # 输出:{1, 2, 3, 4}

# 集合转列表
list_from_set = list(set_from_list)
print(f"集合转列表: {list_from_set}")  # 输出:[1, 2, 3, 4]

# 集合转元组
tuple_from_set = tuple(set_from_list)
print(f"集合转元组: {tuple_from_set}")  # 输出:(1, 2, 3, 4)

在进行这些转换时,需要注意集合是无序且不允许重复元素的,所以将列表或元组转换为集合后再转回来,元素的顺序可能会改变,重复元素会被去除。

字典的转换

字典是键值对的集合,转换操作通常涉及到键、值或键值对的提取

# 示例2:字典相关的转换
student = {'name': 'Alice', 'age': 20, 'courses': ['Math', 'Physics']}

# 获取字典的键并转换为列表
keys_list = list(student.keys())
print(f"字典键转列表: {keys_list}")  # 输出:['name', 'age', 'courses']

# 获取字典的值并转换为元组
values_tuple = tuple(student.values())
print(f"字典值转元组: {values_tuple}")  # 输出:('Alice', 20, ['Math', 'Physics'])

# 获取字典的键值对并转换为列表
items_list = list(student.items())
print(f"字典键值对转列表: {items_list}")  # 输出:[('name', 'Alice'), ('age', 20), ('courses', ['Math', 'Physics'])]

# 将字典的键转换为集合
keys_set = set(student.keys())
print(f"字典键转集合: {keys_set}")  # 输出:{'name', 'age', 'courses'}

还可以从其他集合类型创建字典,只要提供适当的键值对结构

# 示例3:创建字典
# 从键值对列表创建字典
pairs = [('name', 'Bob'), ('age', 25), ('job', 'Developer')]
dict_from_pairs = dict(pairs)
print(f"从键值对列表创建字典: {dict_from_pairs}")
# 输出:{'name': 'Bob', 'age': 25, 'job': 'Developer'}

# 使用zip()将两个列表合并为字典
keys = ['name', 'age', 'job']
values = ['Charlie', 30, 'Designer']
dict_from_zip = dict(zip(keys, values))
print(f"使用zip()创建字典: {dict_from_zip}")
# 输出:{'name': 'Charlie', 'age': 30, 'job': 'Designer'}

# 从具有特定结构的集合创建字典
names = ['David', 'Eva', 'Frank']
ages = [22, 24, 26]
students = {}

for i, name in enumerate(names):
    students[name] = ages[i]

print(f"从单独的集合创建字典: {students}")
# 输出:{'David': 22, 'Eva': 24, 'Frank': 26}

在这些转换中,要注意字典的键必须是可哈希的(即不可变的),所以列表等可变类型不能直接用作字典的键。

三、常见的类型转换错误及解决方法

1. 尝试将非数字字符串转换为数字

最常见的错误之一是尝试将包含非数字字符的字符串转换为数字类型。

# 错误示例:非数字字符串转数字
def demonstrate_string_to_number_errors():
    try:
        # 尝试将含有字母的字符串转换为整数
        num = int("123abc")
    except ValueError as e:
        print(f"错误1: {e}")  # 输出:错误1: invalid literal for int() with base 10: '123abc'
    
    try:
        # 尝试将含有特殊字符的字符串转换为浮点数
        num = float("45.67$")
    except ValueError as e:
        print(f"错误2: {e}")  # 输出:错误2: could not convert string to float: '45.67$'

demonstrate_string_to_number_errors()

# 解决方案
def safe_string_to_number(string, conversion_type):
    """安全地将字符串转换为指定的数字类型。"""
    try:
        if conversion_type == "int":
            # 尝试直接转换为整数
            return int(string)
        elif conversion_type == "float":
            # 尝试直接转换为浮点数
            return float(string)
        else:
            raise ValueError(f"不支持的转换类型: {conversion_type}")
    except ValueError:
        # 如果直接转换失败,尝试清理字符串
        import re
        # 提取所有数字和小数点
        if conversion_type == "int":
            digits = re.sub(r'[^0-9]', '', string)
            return int(digits) if digits else 0
        elif conversion_type == "float":
            matches = re.search(r'[-+]?\d*\.?\d+', string)
            return float(matches.group()) if matches else 0.0

# 测试解决方案
print(safe_string_to_number("123abc", "int"))  # 输出:123
print(safe_string_to_number("45.67$", "float"))  # 输出:45.67
print(safe_string_to_number("价格:$99.99", "float"))  # 输出:99.99

2. 集合类型转换中的陷阱

在进行集合类型转换时,需要注意一些陷阱,比如不可哈希对象和数据丢失问题

# 示例
def demonstrate_collection_conversion_pitfalls():
    # 陷阱1:将包含可变对象的集合转换为集合(不可哈希)
    try:
        list_with_lists = [[1, 2], [3, 4]]
        set_from_list = set(list_with_lists)
    except TypeError as e:
        print(f"错误1: {e}")  # 输出:错误1: unhashable type: 'list'
    
    # 陷阱2:字典键值对转换时的数据丢失
    dict_with_dupe_keys = {'a': 1, 'b': 2, 'a': 3}  # 键'a'重复
    print(f"带有重复键的字典: {dict_with_dupe_keys}")  # 输出:带有重复键的字典: {'a': 3, 'b': 2}
    
    # 陷阱3:从列表创建字典时的键值配对问题
    try:
        items = ['a', 1, 'b', 2, 'c']  # 奇数个元素
        dict_from_items = dict(zip(*[iter(items)]*2))
    except ValueError as e:
        print(f"错误3: {e}")  # 可能输出:错误3: zip argument #2 is shorter than argument #1

demonstrate_collection_conversion_pitfalls()

# 解决方案
def safe_collection_conversions():
    # 解决陷阱1:将嵌套列表转换为包含元组的集合
    list_with_lists = [[1, 2], [3, 4]]
    tuple_list = [tuple(item) for item in list_with_lists]  # 将内部列表转换为元组
    set_from_tuple_list = set(tuple_list)
    print(f"包含元组的集合: {set_from_tuple_list}")  # 输出:包含元组的集合: {(1, 2), (3, 4)}
    
    # 解决陷阱2:显式处理重复键
    items = [('a', 1), ('b', 2), ('a', 3)]
    dict_from_items = {}
    for key, value in items:
        dict_from_items[key] = value  # 后面的值会覆盖前面的
    print(f"从项目显式创建字典: {dict_from_items}")  # 输出:从项目显式创建字典: {'a': 3, 'b': 2}
    
    # 保留所有值(将值存储为列表)
    dict_with_lists = {}
    for key, value in items:
        if key not in dict_with_lists:
            dict_with_lists[key] = []
        dict_with_lists[key].append(value)
    print(f"键对应多个值的字典: {dict_with_lists}")  # 输出:键对应多个值的字典: {'a': [1, 3], 'b': [2]}
    
    # 解决陷阱3:确保键值对的完整性
    items = ['a', 1, 'b', 2, 'c']  # 奇数个元素
    # 添加一个默认值,确保偶数个元素
    if len(items) % 2 != 0:
        items.append(None)
    dict_from_items = dict(zip(items[::2], items[1::2]))
    print(f"从列表创建的字典: {dict_from_items}")  # 输出:从列表创建的字典: {'a': 1, 'b': 2, 'c': None}

safe_collection_conversions()