Skip to main content
☘️ Septvean's Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

数据结构

一、什么是数据结构

数据结构可以理解为:

用什么方式组织、保存和处理数据。

例如,要保存一只股票的信息,可以使用不同的数据结构。

使用多个变量:

code = "600519"
name = "贵州茅台"
price = 1500.0

使用列表:

stock = ["600519", "贵州茅台", 1500.0]

使用字典:

stock = {
    "code": "600519",
    "name": "贵州茅台",
    "price": 1500.0,
}

不同的数据结构,适合不同的场景。

Python 常用的数据结构有:

数据结构 类型 特点
字符串 str 有序、不可修改
列表 list 有序、可修改、可重复
元组 tuple 有序、不可修改、可重复
字典 dict 键值对、可修改、键不可重复
集合 set 无序、可修改、不可重复

二、字符串 str

字符串用于保存文本数据。

name = "Python"
stock_code = "600519"
message = "今天市场上涨"

字符串属于有序数据,可以通过索引访问其中的字符。


1. 创建字符串

可以使用单引号:

name = 'Python'

也可以使用双引号:

name = "Python"

多行字符串可以使用三引号:

text = """
第一行
第二行
第三行
"""

2. 字符串索引

字符串中的每个字符都有一个位置编号,称为索引。

text = "Python"

对应索引:

字符: P  y  t  h  o  n
索引: 0  1  2  3  4  5
反向:-6 -5 -4 -3 -2 -1

访问第一个字符:

text = "Python"

print(text[0])

结果:

P

访问最后一个字符:

print(text[-1])

结果:

n

注意,索引从 0 开始。


3. 字符串切片

切片用于获取字符串的一部分。

基本格式:

字符串[开始位置:结束位置:步长]

例如:

text = "Python"

print(text[0:3])

结果:

Pyt

切片包含开始位置,但不包含结束位置。

常见写法:

text = "Python"

print(text[:3])    # 前三个字符
print(text[3:])    # 从索引 3 到结尾
print(text[:])     # 整个字符串
print(text[::2])   # 每隔一个字符取一次
print(text[::-1])  # 反转字符串

结果:

Pyt
hon
Python
Pto
nohtyP

4. 字符串不可修改

字符串创建后不能直接修改其中的字符。

错误示例:

text = "Python"
text[0] = "J"

会出现错误:

TypeError

正确做法是创建新字符串:

text = "Python"
text = "J" + text[1:]

print(text)

结果:

Jython

5. 字符串拼接

使用 +

first_name = "张"
last_name = "三"

full_name = first_name + last_name

print(full_name)

结果:

张三

字符串重复:

print("Python" * 3)

结果:

PythonPythonPython

6. f-string 格式化

推荐使用 f-string:

name = "张三"
age = 25

message = f"姓名:{name},年龄:{age}"

print(message)

可以直接执行表达式:

price = 20
count = 5

print(f"总价:{price * count} 元")

控制小数位:

price = 12.34567

print(f"{price:.2f}")

结果:

12.35

7. 字符串常用方法

去除两端空白

text = "  Python  "

print(text.strip())

只删除左边:

text.lstrip()

只删除右边:

text.rstrip()

转换大小写

text = "Python"

print(text.lower())
print(text.upper())

结果:

python
PYTHON

首字母大写:

print("python".capitalize())

每个单词首字母大写:

print("hello python".title())

替换内容

text = "Python is easy"

new_text = text.replace("easy", "powerful")

print(new_text)

结果:

Python is powerful

原字符串不会改变。


判断开头和结尾

code = "600519"

print(code.startswith("60"))
print(code.endswith("19"))

结果:

True
True

股票代码判断:

if code.startswith(("00", "60")):
    print("主板股票")

startswith() 可以接收元组。


查找内容

text = "Python is easy"

print(text.find("easy"))

结果:

10

找不到时返回 -1

print(text.find("Java"))

也可以使用成员运算符:

print("Python" in text)
print("Java" not in text)

分割字符串

codes = "600519,000001,300750"

code_list = codes.split(",")

print(code_list)

结果:

["600519", "000001", "300750"]

按空格分割:

text = "Python Java Go"

print(text.split())

限制分割次数:

text = "600519-贵州茅台-白酒"

print(text.split("-", maxsplit=1))

结果:

["600519", "贵州茅台-白酒"]

连接字符串

codes = ["600519", "000001", "300750"]

result = ",".join(codes)

print(result)

结果:

600519,000001,300750

注意,join() 的列表元素必须都是字符串。

错误:

numbers = [1, 2, 3]

",".join(numbers)

正确:

numbers = [1, 2, 3]

result = ",".join(str(number) for number in numbers)

print(result)

判断字符串内容

print("123456".isdigit())
print("Python".isalpha())
print("Python123".isalnum())
print("   ".isspace())

结果:

True
True
True
True

判断股票代码:

def is_valid_code(code: str) -> bool:
    return len(code) == 6 and code.isdigit()

三、列表 list

列表用于保存一组有顺序的数据。

列表的特点:

  • 有顺序
  • 可以修改
  • 可以重复
  • 可以保存不同类型的数据

创建列表:

stocks = ["贵州茅台", "比亚迪", "宁德时代"]

1. 创建列表

空列表:

stocks = []

也可以:

stocks = list()

保存多个数据:

numbers = [10, 20, 30]

保存不同类型:

data = ["600519", "贵州茅台", 1500.0, True]

虽然可以保存不同类型,但实际项目中通常建议保持元素结构一致。


2. 访问列表元素

stocks = ["贵州茅台", "比亚迪", "宁德时代"]

print(stocks[0])
print(stocks[-1])

结果:

贵州茅台
宁德时代

3. 修改列表元素

stocks = ["贵州茅台", "比亚迪", "宁德时代"]

stocks[1] = "中国平安"

print(stocks)

结果:

["贵州茅台", "中国平安", "宁德时代"]

列表是可修改的数据结构。


4. 列表切片

numbers = [10, 20, 30, 40, 50]

print(numbers[1:4])
print(numbers[:3])
print(numbers[2:])
print(numbers[::-1])

结果:

[20, 30, 40]
[10, 20, 30]
[30, 40, 50]
[50, 40, 30, 20, 10]

切片会创建一个新列表。


5. 添加元素

append

在列表末尾添加一个元素:

stocks = ["贵州茅台", "比亚迪"]

stocks.append("宁德时代")

print(stocks)

insert

在指定位置插入元素:

stocks.insert(1, "中国平安")

第一个参数是插入位置。


extend

一次添加多个元素:

stocks = ["贵州茅台"]

stocks.extend(["比亚迪", "宁德时代"])

print(stocks)

也可以使用 +

stocks = ["贵州茅台"] + ["比亚迪", "宁德时代"]

区别是:

  • extend() 修改原列表
  • + 创建新列表

6. 删除元素

remove

按照值删除:

stocks = ["贵州茅台", "比亚迪", "宁德时代"]

stocks.remove("比亚迪")

如果元素不存在,会报错。

安全写法:

if "比亚迪" in stocks:
    stocks.remove("比亚迪")

pop

按照索引删除,并返回被删除的元素:

stocks = ["贵州茅台", "比亚迪", "宁德时代"]

deleted = stocks.pop(1)

print(deleted)
print(stocks)

不传参数时,删除最后一个:

deleted = stocks.pop()

del

删除指定位置:

del stocks[0]

删除切片:

del stocks[1:3]

clear

清空列表:

stocks.clear()

结果:

[]

7. 列表长度

stocks = ["贵州茅台", "比亚迪", "宁德时代"]

print(len(stocks))

结果:

3

8. 判断元素是否存在

stocks = ["贵州茅台", "比亚迪"]

print("贵州茅台" in stocks)
print("宁德时代" not in stocks)

9. 查找和统计

查找元素位置:

stocks = ["贵州茅台", "比亚迪", "宁德时代"]

print(stocks.index("比亚迪"))

结果:

1

统计出现次数:

numbers = [1, 2, 2, 3, 2]

print(numbers.count(2))

结果:

3

10. 列表排序

数字升序:

numbers = [5, 2, 9, 1]

numbers.sort()

print(numbers)

结果:

[1, 2, 5, 9]

降序:

numbers.sort(reverse=True)

sort() 会修改原列表。

如果不想修改原列表,可以使用 sorted()

numbers = [5, 2, 9, 1]

new_numbers = sorted(numbers)

print(numbers)
print(new_numbers)

11. 根据指定字段排序

stocks = [
    {"name": "贵州茅台", "price": 1500},
    {"name": "比亚迪", "price": 300},
    {"name": "中国平安", "price": 50},
]

按价格升序:

stocks.sort(key=lambda stock: stock["price"])

按价格降序:

stocks.sort(
    key=lambda stock: stock["price"],
    reverse=True,
)

也可以使用 sorted()

new_stocks = sorted(
    stocks,
    key=lambda stock: stock["price"],
    reverse=True,
)

12. 反转列表

numbers = [1, 2, 3]

numbers.reverse()

print(numbers)

也可以使用切片:

new_numbers = numbers[::-1]

区别:

  • reverse() 修改原列表
  • [::-1] 创建新列表

13. 列表遍历

stocks = ["贵州茅台", "比亚迪", "宁德时代"]

for stock in stocks:
    print(stock)

获取索引和值:

for index, stock in enumerate(stocks):
    print(index, stock)

从 1 开始编号:

for index, stock in enumerate(stocks, start=1):
    print(index, stock)

14. 列表推导式

普通写法:

squares = []

for number in range(1, 6):
    squares.append(number ** 2)

列表推导式:

squares = [
    number ** 2
    for number in range(1, 6)
]

结果:

[1, 4, 9, 16, 25]

带条件:

even_numbers = [
    number
    for number in range(1, 11)
    if number % 2 == 0
]

结果:

[2, 4, 6, 8, 10]

字符串处理:

codes = [" 600519 ", " 000001 ", " 300750 "]

clean_codes = [
    code.strip()
    for code in codes
]

带条件过滤:

main_board_codes = [
    code
    for code in codes
    if code.startswith(("00", "60"))
]

15. 二维列表

列表中还可以保存列表:

data = [
    ["600519", "贵州茅台", 1500],
    ["000001", "平安银行", 11],
    ["300750", "宁德时代", 300],
]

访问第一行:

print(data[0])

访问第一行第二列:

print(data[0][1])

结果:

贵州茅台

遍历二维列表:

for row in data:
    code = row[0]
    name = row[1]
    price = row[2]

    print(code, name, price)

也可以直接解包:

for code, name, price in data:
    print(code, name, price)

16. 列表复制问题

直接赋值并不是复制:

a = [1, 2, 3]
b = a

b.append(4)

print(a)

结果:

[1, 2, 3, 4]

因为 ab 指向同一个列表。

浅复制:

a = [1, 2, 3]
b = a.copy()

也可以:

b = a[:]

或者:

b = list(a)

修改 b 不会影响 a

b.append(4)

print(a)
print(b)

17. 深拷贝

当列表中还有嵌套列表时,浅复制可能不够。

a = [
    [1, 2],
    [3, 4],
]

b = a.copy()

b[0].append(100)

print(a)

原列表也会发生变化。

需要使用深拷贝:

from copy import deepcopy

a = [
    [1, 2],
    [3, 4],
]

b = deepcopy(a)

b[0].append(100)

print(a)
print(b)

四、元组 tuple

元组和列表类似,但是元组创建后不能修改。

特点:

  • 有顺序
  • 不可修改
  • 可以重复
  • 可以保存不同类型

创建元组:

stock = ("600519", "贵州茅台", 1500.0)

1. 创建元组

numbers = (10, 20, 30)

也可以省略括号:

numbers = 10, 20, 30

空元组:

numbers = ()

2. 单元素元组

单元素元组必须保留逗号:

value = (10,)

下面不是元组:

value = (10)

查看类型:

print(type((10,)))
print(type((10)))

结果:

<class 'tuple'>
<class 'int'>

3. 访问元组元素

stock = ("600519", "贵州茅台", 1500.0)

print(stock[0])
print(stock[-1])

元组也支持切片:

print(stock[:2])

4. 元组不能修改

错误:

stock[1] = "五粮液"

会出现:

TypeError

如果需要修改,可以转换为列表:

stock = ("600519", "贵州茅台", 1500.0)

stock_list = list(stock)
stock_list[1] = "五粮液"

stock = tuple(stock_list)

5. 元组解包

stock = ("600519", "贵州茅台", 1500.0)

code, name, price = stock

print(code)
print(name)
print(price)

变量数量必须与元素数量一致。


6. 使用星号解包

numbers = (1, 2, 3, 4, 5)

first, *middle, last = numbers

print(first)
print(middle)
print(last)

结果:

1
[2, 3, 4]
5

注意,带星号的变量得到的是列表。


7. 交换变量

传统写法:

a = 10
b = 20

temp = a
a = b
b = temp

Python 可以直接写:

a, b = b, a

本质上使用了元组打包和解包。


8. 元组适用场景

元组适合保存不应被修改的数据。

例如坐标:

point = (120.5, 30.2)

RGB 颜色:

color = (255, 128, 0)

数据库一行查询结果:

row = ("600519", "贵州茅台", 1500.0)

函数返回多个值:

def get_stock() -> tuple[str, str, float]:
    return "600519", "贵州茅台", 1500.0

调用:

code, name, price = get_stock()

五、字典 dict

字典使用键值对保存数据。

例如:

stock = {
    "code": "600519",
    "name": "贵州茅台",
    "price": 1500.0,
}

其中:

  • "code" 是键
  • "600519" 是值
  • "name" 是键
  • "贵州茅台" 是值

字典非常适合描述一个对象。


1. 创建字典

空字典:

stock = {}

也可以:

stock = dict()

创建有数据的字典:

stock = {
    "code": "600519",
    "name": "贵州茅台",
    "price": 1500.0,
}

也可以使用 dict()

stock = dict(
    code="600519",
    name="贵州茅台",
    price=1500.0,
)

这种写法要求键是合法变量名。


2. 获取字典值

使用中括号:

print(stock["name"])

结果:

贵州茅台

如果键不存在,会报错:

print(stock["industry"])

更安全的方式是 get()

print(stock.get("industry"))

键不存在时返回 None

设置默认值:

industry = stock.get("industry", "未知行业")

print(industry)

3. 添加键值对

stock["industry"] = "白酒"

此时字典:

{
    "code": "600519",
    "name": "贵州茅台",
    "price": 1500.0,
    "industry": "白酒",
}

4. 修改字典值

stock["price"] = 1520.0

如果键已经存在,就是修改。

如果键不存在,就是新增。


5. update 批量更新

stock.update({
    "price": 1520.0,
    "industry": "白酒",
})

也可以:

stock.update(
    price=1520.0,
    industry="白酒",
)

6. 删除键值对

pop

price = stock.pop("price")

print(price)

如果键可能不存在:

price = stock.pop("price", None)

del

del stock["industry"]

如果键不存在会报错。


popitem

删除最后添加的键值对:

key, value = stock.popitem()

print(key, value)

clear

清空字典:

stock.clear()

7. 判断键是否存在

if "code" in stock:
    print(stock["code"])

判断不存在:

if "industry" not in stock:
    print("没有行业信息")

in 默认判断的是键,而不是值。

判断值:

print("贵州茅台" in stock.values())

8. 获取所有键

print(stock.keys())

转换为列表:

keys = list(stock.keys())

9. 获取所有值

print(stock.values())

转换为列表:

values = list(stock.values())

10. 获取所有键值对

print(stock.items())

结果类似:

dict_items([
    ("code", "600519"),
    ("name", "贵州茅台"),
    ("price", 1500.0),
])

11. 遍历字典

遍历键:

for key in stock:
    print(key)

也可以:

for key in stock.keys():
    print(key)

遍历值:

for value in stock.values():
    print(value)

同时遍历键和值:

for key, value in stock.items():
    print(key, value)

12. 字典嵌套

字典的值也可以是字典:

stock = {
    "code": "600519",
    "name": "贵州茅台",
    "financial": {
        "revenue": 1500,
        "profit": 700,
    },
}

获取嵌套数据:

print(stock["financial"]["profit"])

结果:

700

更安全的写法:

financial = stock.get("financial", {})
profit = financial.get("profit", 0)

print(profit)

13. 列表中保存字典

实际项目中经常使用列表保存多个字典。

stocks = [
    {
        "code": "600519",
        "name": "贵州茅台",
        "price": 1500.0,
    },
    {
        "code": "000001",
        "name": "平安银行",
        "price": 11.5,
    },
    {
        "code": "300750",
        "name": "宁德时代",
        "price": 300.0,
    },
]

遍历:

for stock in stocks:
    code = stock["code"]
    name = stock["name"]
    price = stock["price"]

    print(code, name, price)

筛选主板股票:

main_board_stocks = [
    stock
    for stock in stocks
    if stock["code"].startswith(("00", "60"))
]

筛选价格大于 100:

expensive_stocks = [
    stock
    for stock in stocks
    if stock["price"] > 100
]

14. 字典推导式

普通写法:

squares = {}

for number in range(1, 6):
    squares[number] = number ** 2

字典推导式:

squares = {
    number: number ** 2
    for number in range(1, 6)
}

结果:

{
    1: 1,
    2: 4,
    3: 9,
    4: 16,
    5: 25,
}

交换键和值:

stock_codes = {
    "贵州茅台": "600519",
    "平安银行": "000001",
}

code_names = {
    code: name
    for name, code in stock_codes.items()
}

15. 使用 setdefault

当键不存在时设置默认值:

stock = {
    "code": "600519",
}
stock.setdefault("name", "未知")

如果键不存在,就添加:

{
    "code": "600519",
    "name": "未知",
}

如果键已经存在,不会覆盖:

stock.setdefault("code", "000001")

code 仍然是 "600519"


16. 使用字典统计频率

统计字符出现次数:

text = "hello"
counts = {}

for char in text:
    counts[char] = counts.get(char, 0) + 1

print(counts)

结果:

{
    "h": 1,
    "e": 1,
    "l": 2,
    "o": 1,
}

统计股票代码前两位:

codes = [
    "600519",
    "000001",
    "002594",
    "300750",
    "603259",
    "000858",
]

prefix_counts = {}

for code in codes:
    prefix = code[:2]
    prefix_counts[prefix] = prefix_counts.get(prefix, 0) + 1

print(prefix_counts)

六、集合 set

集合用于保存不重复的数据。

特点:

  • 元素不重复
  • 没有固定索引
  • 可以进行交集、并集、差集运算
  • 适合去重和成员判断

1. 创建集合

numbers = {1, 2, 3, 4}

重复元素会自动去除:

numbers = {1, 2, 2, 3, 3, 4}

print(numbers)

结果:

{1, 2, 3, 4}

2. 创建空集合

正确:

numbers = set()

错误:

numbers = {}

{} 创建的是空字典。


3. 列表去重

codes = [
    "600519",
    "000001",
    "600519",
    "300750",
]

unique_codes = set(codes)

print(unique_codes)

如果需要列表:

unique_codes = list(set(codes))

注意,集合不保证原顺序。


4. 保持顺序去重

如果需要保持原顺序,不建议直接使用 set()

写法一:

codes = [
    "600519",
    "000001",
    "600519",
    "300750",
]

result = []

for code in codes:
    if code not in result:
        result.append(code)

print(result)

更高效的写法:

result = []
seen = set()

for code in codes:
    if code in seen:
        continue

    seen.add(code)
    result.append(code)

还可以利用字典保持顺序:

result = list(dict.fromkeys(codes))

5. 添加元素

codes = {"600519", "000001"}

codes.add("300750")

添加多个元素:

codes.update([
    "002594",
    "603259",
])

6. 删除元素

remove

codes.remove("600519")

元素不存在时会报错。


discard

codes.discard("600519")

元素不存在时不会报错。

通常在不确定元素是否存在时,优先使用 discard()


pop

随机删除并返回一个元素:

code = codes.pop()

因为集合无固定顺序,所以不能确定删除哪个元素。


clear

codes.clear()

7. 集合并集

a = {"600519", "000001"}
b = {"000001", "300750"}

使用 |

result = a | b

结果:

{"600519", "000001", "300750"}

也可以:

result = a.union(b)

8. 集合交集

找出两个集合都包含的数据:

result = a & b

结果:

{"000001"}

也可以:

result = a.intersection(b)

实际场景:

watch_list = {
    "600519",
    "000001",
    "300750",
}

rising_stocks = {
    "000001",
    "300750",
    "002594",
}

watched_rising_stocks = watch_list & rising_stocks

print(watched_rising_stocks)

结果:

{"000001", "300750"}

9. 集合差集

找出在 a 中但不在 b 中的数据:

result = a - b

也可以:

result = a.difference(b)

实际场景:

all_codes = {
    "600519",
    "000001",
    "300750",
}

excluded_codes = {
    "000001",
}

result = all_codes - excluded_codes

结果:

{"600519", "300750"}

10. 对称差集

找出只出现在其中一个集合中的元素:

result = a ^ b

也可以:

result = a.symmetric_difference(b)

11. 子集和超集

a = {1, 2}
b = {1, 2, 3, 4}

判断 a 是否为 b 的子集:

print(a <= b)
print(a.issubset(b))

判断 b 是否为 a 的超集:

print(b >= a)
print(b.issuperset(a))

判断是否没有共同元素:

a = {1, 2}
b = {3, 4}

print(a.isdisjoint(b))

结果:

True

12. 集合推导式

squares = {
    number ** 2
    for number in range(1, 6)
}

筛选偶数:

even_numbers = {
    number
    for number in range(1, 11)
    if number % 2 == 0
}

七、可变与不可变

理解可变和不可变,是掌握 Python 数据结构的重要基础。

1. 可变类型

创建后可以修改:

  • list
  • dict
  • set

例如:

numbers = [1, 2, 3]
numbers.append(4)

原列表被修改。


2. 不可变类型

创建后不能修改:

  • str
  • tuple
  • int
  • float
  • bool

例如:

text = "Python"
text.upper()

upper() 返回新字符串,不会修改原字符串。

text = "Python"

new_text = text.upper()

print(text)
print(new_text)

结果:

Python
PYTHON

八、对象引用

Python 变量保存的不是数据本身,而是对象的引用。

a = [1, 2, 3]
b = a

此时 ab 指向同一个列表。

b.append(4)

print(a)

结果:

[1, 2, 3, 4]

可以使用 id() 查看对象标识:

print(id(a))
print(id(b))

两者相同。

如果需要复制:

b = a.copy()

九、判断相等和判断同一个对象

1. ==

判断值是否相等:

a = [1, 2, 3]
b = [1, 2, 3]

print(a == b)

结果:

True

2. is

判断是否为同一个对象:

print(a is b)

结果:

False

因为它们的内容相同,但不是同一个列表对象。

is 最常用于判断 None

result = None

if result is None:
    print("没有结果")

不推荐:

if result == None:
    pass

推荐:

if result is None:
    pass

十、数据结构之间的转换

1. 字符串转列表

text = "600519,000001,300750"

codes = text.split(",")

print(codes)

2. 列表转字符串

codes = ["600519", "000001", "300750"]

text = ",".join(codes)

3. 列表转元组

numbers = [1, 2, 3]

result = tuple(numbers)

4. 元组转列表

numbers = (1, 2, 3)

result = list(numbers)

5. 列表转集合

numbers = [1, 2, 2, 3]

result = set(numbers)

适合去重。


6. 集合转列表

numbers = {1, 2, 3}

result = list(numbers)

7. 列表转字典

键值对列表:

items = [
    ("code", "600519"),
    ("name", "贵州茅台"),
    ("price", 1500.0),
]

stock = dict(items)

结果:

{
    "code": "600519",
    "name": "贵州茅台",
    "price": 1500.0,
}

8. 两个列表转字典

keys = ["code", "name", "price"]
values = ["600519", "贵州茅台", 1500.0]

stock = dict(zip(keys, values))

结果:

{
    "code": "600519",
    "name": "贵州茅台",
    "price": 1500.0,
}

十一、zip 的使用

zip() 用于同时组合多个可迭代对象。

codes = [
    "600519",
    "000001",
    "300750",
]

names = [
    "贵州茅台",
    "平安银行",
    "宁德时代",
]

同时遍历:

for code, name in zip(codes, names):
    print(code, name)

转换为字典:

stocks = dict(zip(codes, names))

结果:

{
    "600519": "贵州茅台",
    "000001": "平安银行",
    "300750": "宁德时代",
}

注意,zip() 会以最短的数据长度为准。


十二、enumerate 的使用

enumerate() 用于同时获取索引和值。

stocks = [
    "贵州茅台",
    "平安银行",
    "宁德时代",
]
for index, stock in enumerate(stocks):
    print(index, stock)

结果:

0 贵州茅台
1 平安银行
2 宁德时代

从 1 开始:

for index, stock in enumerate(stocks, start=1):
    print(index, stock)

结果:

1 贵州茅台
2 平安银行
3 宁德时代

十三、常用内置函数

len

获取元素数量:

print(len([1, 2, 3]))
print(len({"a": 1, "b": 2}))
print(len("Python"))

max 和 min

numbers = [10, 5, 30, 8]

print(max(numbers))
print(min(numbers))

字典列表中获取价格最高的股票:

stocks = [
    {"name": "贵州茅台", "price": 1500},
    {"name": "平安银行", "price": 11},
    {"name": "宁德时代", "price": 300},
]

highest_stock = max(
    stocks,
    key=lambda stock: stock["price"],
)

print(highest_stock)

sum

numbers = [10, 20, 30]

print(sum(numbers))

计算股票总市值:

stocks = [
    {"name": "A", "market_value": 100},
    {"name": "B", "market_value": 200},
    {"name": "C", "market_value": 300},
]

total_market_value = sum(
    stock["market_value"]
    for stock in stocks
)

sorted

numbers = [5, 2, 9, 1]

new_numbers = sorted(numbers)

按字符串长度排序:

names = [
    "贵州茅台",
    "平安银行",
    "工业富联",
]

result = sorted(names, key=len)

any

只要有一个元素为真,就返回 True

results = [False, False, True]

print(any(results))

判断是否有主板代码:

codes = ["300750", "688981", "600519"]

has_main_board = any(
    code.startswith(("00", "60"))
    for code in codes
)

print(has_main_board)

all

所有元素都为真,才返回 True

results = [True, True, True]

print(all(results))

判断所有代码是否合法:

codes = ["600519", "000001", "300750"]

all_valid = all(
    len(code) == 6 and code.isdigit()
    for code in codes
)

print(all_valid)

十四、数据结构选择原则

使用字符串

适合保存文本:

name = "贵州茅台"
code = "600519"

股票代码虽然全是数字,但应该使用字符串。

因为:

code = "000001"

如果使用整数:

code = 1

前面的零会丢失。


使用列表

适合保存一组有顺序的数据:

codes = [
    "600519",
    "000001",
    "300750",
]

需要:

  • 保持顺序
  • 允许重复
  • 经常添加、删除、修改

使用列表。


使用元组

适合保存不应该修改的数据:

point = (120.5, 30.2)

或者函数返回固定结构:

def get_user():
    return "张三", 25

使用字典

适合描述一个对象:

stock = {
    "code": "600519",
    "name": "贵州茅台",
    "price": 1500.0,
}

当数据具有明确字段名称时,优先考虑字典。


使用集合

适合:

  • 去重
  • 快速判断元素是否存在
  • 集合运算
excluded_codes = {
    "600519",
    "000001",
}

判断代码是否排除:

if code in excluded_codes:
    print("排除该股票")

集合成员判断通常比列表更高效。


十五、综合案例:整理股票数据

原始数据:

stocks = [
    {
        "code": " 600519 ",
        "name": "贵州茅台",
        "price": 1500.0,
        "industry": "白酒",
    },
    {
        "code": "000001",
        "name": "平安银行",
        "price": 11.5,
        "industry": "银行",
    },
    {
        "code": "600519",
        "name": "贵州茅台",
        "price": 1500.0,
        "industry": "白酒",
    },
    {
        "code": "300750",
        "name": "宁德时代",
        "price": 300.0,
        "industry": "电池",
    },
]

需求:

  1. 清理代码两端空格。
  2. 删除重复股票。
  3. 筛选主板股票。
  4. 按价格降序排列。
  5. 按行业统计数量。

完整代码:

stocks = [
    {
        "code": " 600519 ",
        "name": "贵州茅台",
        "price": 1500.0,
        "industry": "白酒",
    },
    {
        "code": "000001",
        "name": "平安银行",
        "price": 11.5,
        "industry": "银行",
    },
    {
        "code": "600519",
        "name": "贵州茅台",
        "price": 1500.0,
        "industry": "白酒",
    },
    {
        "code": "300750",
        "name": "宁德时代",
        "price": 300.0,
        "industry": "电池",
    },
]

清理代码:

for stock in stocks:
    stock["code"] = stock["code"].strip()

按照代码去重:

unique_stocks = []
seen_codes = set()

for stock in stocks:
    code = stock["code"]

    if code in seen_codes:
        continue

    seen_codes.add(code)
    unique_stocks.append(stock)

筛选主板股票:

main_board_stocks = [
    stock
    for stock in unique_stocks
    if stock["code"].startswith(("00", "60"))
]

按照价格降序:

main_board_stocks.sort(
    key=lambda stock: stock["price"],
    reverse=True,
)

统计行业数量:

industry_counts = {}

for stock in unique_stocks:
    industry = stock["industry"]

    industry_counts[industry] = (
        industry_counts.get(industry, 0) + 1
    )

输出结果:

for stock in main_board_stocks:
    print(
        stock["code"],
        stock["name"],
        stock["price"],
    )

print(industry_counts)

完整函数:

def process_stocks(
    stocks: list[dict[str, object]],
) -> tuple[
    list[dict[str, object]],
    dict[str, int],
]:
    unique_stocks: list[dict[str, object]] = []
    seen_codes: set[str] = set()

    for stock in stocks:
        code = str(stock.get("code", "")).strip()
        stock["code"] = code

        if code in seen_codes:
            continue

        seen_codes.add(code)
        unique_stocks.append(stock)

    main_board_stocks = [
        stock
        for stock in unique_stocks
        if str(stock["code"]).startswith(("00", "60"))
    ]

    main_board_stocks.sort(
        key=lambda stock: float(stock.get("price", 0)),
        reverse=True,
    )

    industry_counts: dict[str, int] = {}

    for stock in unique_stocks:
        industry = str(
            stock.get("industry", "未知行业")
        )

        industry_counts[industry] = (
            industry_counts.get(industry, 0) + 1
        )

    return main_board_stocks, industry_counts

调用:

main_board_stocks, industry_counts = (
    process_stocks(stocks)
)

print(main_board_stocks)
print(industry_counts)

十六、常见错误

1. 修改列表时同时遍历

不推荐:

numbers = [1, 2, 3, 4, 5]

for number in numbers:
    if number % 2 == 0:
        numbers.remove(number)

遍历过程中修改列表,容易漏掉元素。

推荐创建新列表:

numbers = [1, 2, 3, 4, 5]

numbers = [
    number
    for number in numbers
    if number % 2 != 0
]

2. 使用不存在的字典键

容易报错:

price = stock["price"]

更安全:

price = stock.get("price", 0)

但如果字段必须存在,使用中括号反而更合适,因为可以及时暴露数据问题。


3. 混淆 append 和 extend

numbers = [1, 2]

使用 append()

numbers.append([3, 4])

结果:

[1, 2, [3, 4]]

使用 extend()

numbers = [1, 2]

numbers.extend([3, 4])

结果:

[1, 2, 3, 4]

4. 混淆 remove 和 pop

remove() 按值删除:

numbers.remove(20)

pop() 按索引删除:

numbers.pop(1)

5. 把空集合写成大括号

错误:

data = {}

这是字典。

正确:

data = set()

6. 使用可变对象作为默认参数

不推荐:

def add_item(
    item: str,
    items: list[str] = [],
) -> list[str]:
    items.append(item)
    return items

默认列表会被多次调用共享。

推荐:

def add_item(
    item: str,
    items: list[str] | None = None,
) -> list[str]:
    if items is None:
        items = []

    items.append(item)

    return items

十七、练习题

练习一

给定列表:

numbers = [1, 2, 2, 3, 4, 4, 5]

删除重复元素并保持原顺序。

参考答案:

result = list(dict.fromkeys(numbers))

print(result)

练习二

给定股票代码:

codes = [
    "600519",
    "000001",
    "300750",
    "603259",
    "002594",
]

筛选以 0060 开头的代码。

参考答案:

result = [
    code
    for code in codes
    if code.startswith(("00", "60"))
]

print(result)

练习三

统计列表中每个行业出现次数:

industries = [
    "银行",
    "白酒",
    "银行",
    "半导体",
    "白酒",
    "银行",
]

参考答案:

counts = {}

for industry in industries:
    counts[industry] = counts.get(industry, 0) + 1

print(counts)

练习四

给定股票列表:

stocks = [
    {"name": "贵州茅台", "price": 1500},
    {"name": "平安银行", "price": 11},
    {"name": "宁德时代", "price": 300},
]

找出价格最高的股票。

参考答案:

highest_stock = max(
    stocks,
    key=lambda stock: stock["price"],
)

print(highest_stock)

练习五

找出两个股票列表中共同出现的代码。

list_a = [
    "600519",
    "000001",
    "300750",
]

list_b = [
    "000001",
    "300750",
    "002594",
]

参考答案:

result = set(list_a) & set(list_b)

print(result)

练习六

将下面两个列表组合成字典:

codes = [
    "600519",
    "000001",
]

names = [
    "贵州茅台",
    "平安银行",
]

参考答案:

stocks = dict(zip(codes, names))

print(stocks)

练习七

将列表中的股票按照价格降序排列:

stocks = [
    {"name": "A公司", "price": 20},
    {"name": "B公司", "price": 50},
    {"name": "C公司", "price": 10},
]

参考答案:

stocks.sort(
    key=lambda stock: stock["price"],
    reverse=True,
)

print(stocks)

十八、数据结构核心总结

字符串:

text = "Python"

适合保存文本,不能直接修改。

列表:

items = [1, 2, 3]

适合保存有顺序、需要修改的数据。

元组:

point = (10, 20)

适合保存固定、不应修改的数据。

字典:

user = {
    "name": "张三",
    "age": 25,
}

适合保存具有字段名称的对象数据。

集合:

codes = {
    "600519",
    "000001",
}

适合去重、成员判断和集合运算。

选择数据结构时,可以先问自己四个问题:

数据是否需要保持顺序?
数据是否允许重复?
数据是否需要修改?
数据是否具有明确的字段名称?

常见选择:

数据类型 数据结构
一段文本 字符串
一组有序数据 列表
固定不变的一组数据 元组
一个具有多个属性的对象 字典
一组不能重复的数据 集合
多个对象 列表 + 字典

实际 Python 项目中,最常见的组合是:

list[dict]

例如:

stocks = [
    {
        "code": "600519",
        "name": "贵州茅台",
    },
    {
        "code": "000001",
        "name": "平安银行",
    },
]

掌握字符串、列表、字典和集合,已经可以处理大部分日常数据整理任务。