鱼C论坛

 找回密码
 立即注册
查看: 41|回复: 11

[已解决]openpyxl问题

[复制链接]
发表于 5 小时前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
  1. import os
  2. from openpyxl import load_workbook

  3. file_path = os.path.join("try01","临考记忆点.xlsx")

  4. # 1.获取workbook对象
  5. work_book_object = load_workbook(file_path)

  6. sheet_object = work_book_object["Sheet1"]


  7. # 获取合并的单元格,如果是被合并的单元格 让值默认等于 -
  8. from openpyxl.cell.cell import Cell,MergedCell
  9. row_text_list = []
  10. for row in sheet_object.rows:

  11.     for cell in row:
  12.         if type(cell) == Cell:
  13.             row_text_list.append(cell.value)
  14.         elif type(cell) == MergedCell:
  15.             row_text_list.append("-")
  16. # print(row_text_list)
  17.         for i in row_text_list:
  18.             if i == "-" or i == None:
  19.                 row_text_list.remove(i)
  20. print(row_text_list)
复制代码

  1. import os
  2. from openpyxl import load_workbook

  3. file_path = os.path.join("try01","临考记忆点.xlsx")

  4. # 1.获取workbook对象
  5. work_book_object = load_workbook(file_path)

  6. sheet_object = work_book_object["Sheet1"]


  7. # 获取合并的单元格,如果是被合并的单元格 让值默认等于 -
  8. from openpyxl.cell.cell import Cell,MergedCell
  9. row_text_list = []
  10. for row in sheet_object.rows:

  11.     for cell in row:
  12.         if type(cell) == Cell:
  13.             row_text_list.append(cell.value)
  14.         elif type(cell) == MergedCell:
  15.             row_text_list.append("-")
  16. # print(row_text_list)
  17. for i in row_text_list:
  18.     if i == "-" or i == None:
  19.         row_text_list.remove(i)
  20. print(row_text_list)
复制代码

我有一个excel表格,其中有很多合并后的单元格,为什么这两段代码处理后 输出的结果会不一样,第一段代码是我想要的结果,而第二段代码处理的结果前面是我想要的结果从中间开始就感觉没有处理了
最佳答案
5 小时前
你遇到的问题是因为在迭代列表的同时修改列表内容导致的。让我们分析一下两段代码的区别:

第一段代码(正确):

  1. for i in row_text_list:
  2.     if i == "-" or i == None:
  3.         row_text_list.remove(i)
复制代码


第二段代码(有问题):

  1.         for i in row_text_list:
  2.             if i == "-" or i == None:
  3.                 row_text_list.remove(i)
复制代码


关键区别:

第二段代码的 for i in row_text_list: 循环缩进错误,它被放在了 for cell in row: 循环内部,这意味着:
1. 每处理一个单元格,就会对整个 row_text_list 进行一次遍历和删除操作
2. 这会导致循环逻辑混乱,容易跳过某些元素

问题原因:

在遍历列表的同时删除元素会导致问题,因为 Python 的迭代器会"丢失"一些元素。例如:
- 列表:[1, "-", 2, "-", 3]
- 删除第一个 "-" 后:[1, 2, "-", 3]
- 但迭代器已经移动到下一个位置,会跳过 2

解决方案:

推荐使用列表推导式来过滤,这样更清晰且不会出错:


  1. import os
  2. from openpyxl import load_workbook
  3. from openpyxl.cell.cell import Cell, MergedCell

  4. file_path = os.path.join("try01", "临考记忆点.xlsx")
  5. work_book_object = load_workbook(file_path)
  6. sheet_object = work_book_object.active  # 注意:这里应该是获取具体的工作表

  7. row_text_list = []
  8. for row in sheet_object.rows:
  9.     for cell in row:
  10.         if isinstance(cell, Cell):
  11.             row_text_list.append(cell.value)
  12.         elif isinstance(cell, MergedCell):
  13.             row_text_list.append("-")

  14. # 使用列表推导式过滤
  15. row_text_list = [item for item in row_text_list if item not in ("-", None)]
  16. print(row_text_list)
复制代码


注意事项:

1. sheet_object = work_book_object 应该是 sheet_object = work_book_object.active 或其他具体的工作表
2. 使用 isinstance(cell, Cell)type(cell) == Cell 更规范
3. 推荐使用列表推导式而不是在迭代中删除元素

如果你的代码确实需要按照原来的逻辑,可以这样修复第二段代码:


  1. # 创建一个临时列表来存储要删除的索引
  2. to_remove = []
  3. for index, i in enumerate(row_text_list):
  4.     if i == "-" or i is None:
  5.         to_remove.append(index)

  6. # 从后往前删除,避免索引错位
  7. for index in reversed(to_remove):
  8.     del row_text_list[index]
复制代码


以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 5 小时前 | 显示全部楼层    本楼为最佳答案   
你遇到的问题是因为在迭代列表的同时修改列表内容导致的。让我们分析一下两段代码的区别:

第一段代码(正确):

  1. for i in row_text_list:
  2.     if i == "-" or i == None:
  3.         row_text_list.remove(i)
复制代码


第二段代码(有问题):

  1.         for i in row_text_list:
  2.             if i == "-" or i == None:
  3.                 row_text_list.remove(i)
复制代码


关键区别:

第二段代码的 for i in row_text_list: 循环缩进错误,它被放在了 for cell in row: 循环内部,这意味着:
1. 每处理一个单元格,就会对整个 row_text_list 进行一次遍历和删除操作
2. 这会导致循环逻辑混乱,容易跳过某些元素

问题原因:

在遍历列表的同时删除元素会导致问题,因为 Python 的迭代器会"丢失"一些元素。例如:
- 列表:[1, "-", 2, "-", 3]
- 删除第一个 "-" 后:[1, 2, "-", 3]
- 但迭代器已经移动到下一个位置,会跳过 2

解决方案:

推荐使用列表推导式来过滤,这样更清晰且不会出错:


  1. import os
  2. from openpyxl import load_workbook
  3. from openpyxl.cell.cell import Cell, MergedCell

  4. file_path = os.path.join("try01", "临考记忆点.xlsx")
  5. work_book_object = load_workbook(file_path)
  6. sheet_object = work_book_object.active  # 注意:这里应该是获取具体的工作表

  7. row_text_list = []
  8. for row in sheet_object.rows:
  9.     for cell in row:
  10.         if isinstance(cell, Cell):
  11.             row_text_list.append(cell.value)
  12.         elif isinstance(cell, MergedCell):
  13.             row_text_list.append("-")

  14. # 使用列表推导式过滤
  15. row_text_list = [item for item in row_text_list if item not in ("-", None)]
  16. print(row_text_list)
复制代码


注意事项:

1. sheet_object = work_book_object 应该是 sheet_object = work_book_object.active 或其他具体的工作表
2. 使用 isinstance(cell, Cell)type(cell) == Cell 更规范
3. 推荐使用列表推导式而不是在迭代中删除元素

如果你的代码确实需要按照原来的逻辑,可以这样修复第二段代码:


  1. # 创建一个临时列表来存储要删除的索引
  2. to_remove = []
  3. for index, i in enumerate(row_text_list):
  4.     if i == "-" or i is None:
  5.         to_remove.append(index)

  6. # 从后往前删除,避免索引错位
  7. for index in reversed(to_remove):
  8.     del row_text_list[index]
复制代码


以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 5 小时前 | 显示全部楼层

for i in row_text_list:
    if i == "-" or i == None:
        row_text_list.remove(i)
这样写的代码,得到却跟用推导式得到的结果不一样
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 5 小时前 | 显示全部楼层
735468682 发表于 2026-01-20 12:00
for i in row_text_list:
    if i == "-" or i == N ...


你的观察是对的,问题在于在循环中修改正在迭代的列表会导致元素被跳过。让我详细解释一下:

假设 row_text_list =

使用 for i in row_text_list: 遍历:
1. 第一次:i = "-",满足条件,删除 "-" → 列表变为
2. 第二次:i = "A",不满足条件
3. 第三次:i = "B",不满足条件
4. 第四次:i = "-",满足条件,删除 "-" → 列表变为
5. 列表结束

结果是 ,而推导式的结果是

看,被跳过了!这就是问题所在。

为什么会这样?
当你在循环中删除元素时,列表索引会发生变化,但循环的迭代器仍按原来的索引前进。

正确的解决方案:
1. 使用列表推导式(最推荐):

  1. row_text_list = [i for i in row_text_list if i != "-" and i is not None]
复制代码


2. 如果要保持 for 循环,可以从后往前删除:

  1. for i in range(len(row_text_list)-1, -1, -1):
  2.     if row_text_list[i] == "-" or row_text_list[i] is None:
  3.         del row_text_list[i]
复制代码


3. 或者创建新列表:

  1. new_list = []
  2. for i in row_text_list:
  3.     if i != "-" and i is not None:
  4.         new_list.append(i)
  5. row_text_list = new_list
复制代码


推荐使用列表推导式,因为:
1. 代码更简洁
2. 没有修改迭代中的列表,不会出错
3. 性能通常更好

注意:判断 None 应该用 i is None 而不是 i == None,虽然两者通常结果一样,但 is None 更规范。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 4 小时前 | 显示全部楼层
还是有点没懂  

  1. for i in row_text_list:
  2.     if i == "-" or i == None:
  3.         row_text_list.remove(i)
复制代码

我的意思是这样写得到的结果并不是我想要的

  1.         for i in row_text_list:
  2.             if i == "-" or i == None:
  3.                 row_text_list.remove(i)
复制代码

反而这样写,才得到我想要的结果且与推导式结果一致
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 4 小时前 | 显示全部楼层
735468682 发表于 2026-01-20 12:07
还是有点没懂   
for i in row_text_list:
    if i ...


你观察到的现象完全正确!让我用一个简单的例子来演示这个问题:

假设 row_text_list =

执行这个循环:


for i in row_text_list:
    print(f"检查: {i}")
    if i == "-" or i == None:
        print(f"删除: {i}")
        row_text_list.remove(i)


实际执行过程是这样的:
1. 检查 "-" → 删除 "-" → 列表变为
2. 检查 "B" (不是 "-" 或 None) → 列表不变
3. 检查 "-" → 删除 "-" → 列表变为
4. 检查 "D" (不是 "-" 或 None) → 列表不变
5. 结束

结果:

而推导式: 的结果是

这就是为什么你用 for 循环删除得到的结果不正确。

但如果是这样写的代码:


        for i in row_text_list:
            if i == "-" or i == None:
                row_text_list.remove(i)


注意:这里的关键是 缩进!如果这个循环是在另一个循环内部,每处理一个单元格就执行一次,情况就会不同:

假设 row_text_list 初始为空,逐步添加元素:

第一次添加:"-"
执行循环:删除 "-" → 列表为空

第二次添加:"A"
执行循环:不删除 → 列表为

第三次添加:"B"
执行循环:不删除 → 列表为

第四次添加:"-"
执行循环:删除 "-" → 列表为

这样最终结果可能正确,但这是巧合!

核心问题:
1. 在遍历列表的同时修改列表会导致元素被跳过
2. 推导式创建的是新列表,不会修改正在遍历的列表

建议:
始终使用推导式来过滤列表,这是最可靠的方法。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 4 小时前 | 显示全部楼层
还有 推导式中 not in 是什么意思
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 4 小时前 | 显示全部楼层
735468682 发表于 2026-01-20 12:12
还有 推导式中 not in 是什么意思


在推导式中,not in 是一个成员运算符,用来检查某个元素不在指定的序列中。让我用例子来解释:

1. 基本语法:

not in 返回布尔值(True 或 False):
元素 not in 序列 如果元素不在序列中,返回 True

2. 简单例子:


  1. # 检查元素是否不在列表中
  2. fruits =

  3. print("apple" not in fruits)  # 输出: False(因为 apple 在列表中)
  4. print("banana" not in fruits)  # 输出: True(因为 banana 不在列表中)
复制代码


3. 在推导式中使用 not in:


  1. # 原始数据
  2. numbers =

  3. # 筛选出不在 [2, 4, 6] 中的数字
  4. result =
  5. print(result)  # 输出: [1, 3, 5, 7, 8, 9]
复制代码


4. 应用到你的案例:

对于你的需求(排除 "-" 和 None),可以这样写:

方法1:使用 and(推荐)

  1. row_text_list =
复制代码


方法2:使用 not in

  1. exclude =
  2. row_text_list =
复制代码


5. 注意事项:
1. None 的判断最好用 is Noneis not None,这样更准确
2. 如果要用 not in 判断 None,需要确保序列中包含 None
3. not in 的优先级低于 andor

建议:对于你的具体需求,使用第一种方法(i != "-" and i is not None)更清晰易懂。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 4 小时前 | 显示全部楼层
FishC 发表于 2026-1-20 12:08
你观察到的现象完全正确!让我用一个简单的例子来演示这个问题:

假设 row_text_list =

那如果我用循环的话,最好是新建列表,重新添加非“-”和None的元素,才能确保正确?
  1. new_list = []
  2. for i in row_text_list:
  3.     if i != "-" or i is not None:
  4.         new_list.append(i)
  5. print(new_list)
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 4 小时前 | 显示全部楼层
735468682 发表于 2026-01-20 12:18
FishC 发表于 2026-1-20 12:08
你观察到的现象完全正 ...


是的,用循环创建新列表是最安全的方法。但是你的代码逻辑需要修正一下。

你的代码:
  1. new_list = []
  2. for i in row_text_list:
  3.     if i != "-" or i is not None:
  4.         new_list.append(i)
  5. print(new_list)
复制代码


这个逻辑有问题!用 or 连接会导致:
- 如果 i 是 "-":i != "-" 为 False,但 i is not None 为 True,结果 True → 会被添加(错误!)
- 如果 i 是 None:i != "-" 为 True,但 i is not None 为 False,结果 True → 会被添加(错误!)

正确的应该是用 and:

  1. new_list = []
  2. for i in row_text_list:
  3.     if i != "-" and i is not None:
  4.         new_list.append(i)
  5. print(new_list)
复制代码


或者更简洁的写法:

  1. new_list = []
  2. for i in row_text_list:
  3.     # 只有当元素不是 "-" 且不是 None 时才添加
  4.     if i not in ("-", None):
  5.         new_list.append(i)
  6. print(new_list)
复制代码


这个方法的优点是:
1. 不会修改正在遍历的列表,所以不会出现跳过的错误
2. 逻辑清晰,易于理解
3. 结果与推导式完全一致

另一种思考方式是反过来写:

  1. new_list = []
  2. for i in row_text_list:
  3.     # 如果元素是 "-" 或 None,就跳过
  4.     if i == "-" or i is None:
  5.         continue  # 跳过本次循环,不添加到新列表
  6.     new_list.append(i)
  7. print(new_list)
复制代码


总结:用循环新建列表时,关键是:
1. 不要修改正在遍历的列表
2. 正确使用逻辑运算符(and 而不是 or)
3. 可以结合 continue 语句使逻辑更清晰

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 8 分钟前 | 显示全部楼层
  1. import os
  2. from openpyxl import load_workbook

  3. file_path = os.path.join("try01","临考记忆点.xlsx")

  4. # 1.获取workbook对象
  5. work_book_object = load_workbook(file_path)

  6. sheet_object = work_book_object["Sheet1"]


  7. # 获取合并的单元格,如果是被合并的单元格 让值默认等于 -
  8. from openpyxl.cell.cell import Cell,MergedCell
  9. row_text_list = []
  10. for row in sheet_object.rows:

  11.     for cell in row:
  12.         if type(cell) == Cell and cell.value is not None:
  13.             row_text_list.append(cell.value)
  14. print(row_text_list):
复制代码

如果我只想得到不含"None"和“-”的列表  直接这样写是不是连推导式都可以不需要了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 6 分钟前 | 显示全部楼层
735468682 发表于 2026-01-20 16:57
import os
from openpyxl import load_workbook

f ...


是的,完全正确!你现在的代码已经实现了相同的过滤效果。

让我们分析一下你修改后的代码:


  1. import os
  2. from openpyxl import load_workbook

  3. file_path = os.path.join("try01","临考记忆点.xlsx")

  4. # 1.获取workbook对象
  5. work_book_object = load_workbook(file_path)

  6. sheet_object = work_book_object

  7. # 获取合并的单元格,如果是被合并的单元格 让值默认等于 -
  8. from openpyxl.cell.cell import Cell,MergedCell
  9. row_text_list =
  10. for row in sheet_object.rows:

  11.     for cell in row:
  12.         if type(cell) == Cell and cell.value is not None:
  13.             row_text_list.append(cell.value)
  14. print(row_text_list)
复制代码


这个代码的优点:
1. 在添加的时候就进行过滤:只添加类型为 Cell 且值不为 None 的元素
2. 直接跳过了合并单元格(MergedCell 类型)
3. 不需要后续的推导式或循环再过滤

这与推导式的效果是等价的。这两种方式你会得到相同的结果:

推导式方法:

  1. row_text_list =
  2. row_text_list =
  3. print(row_text_list)
复制代码


你的方法:

  1. row_text_list =
  2. for cell in sheet_object.rows中的所有cell:
  3.     if 是普通单元格且值不为None:
  4.         row_text_list.append(cell.value)
  5. print(row_text_list)
复制代码


但是要注意几个小细节:

1. sheet_object = work_book_object 应该是 sheet_object = work_book_object.active(或指定具体的工作表)

2. 对于合并单元格,你现在的代码完全跳过了它们,包括合并区域左上角的那个有值的单元格也会被跳过,因为它虽然是 Cell 类型,但如果你不检查它是合并单元格的一部分,可能会丢失数据。

更完整的写法应该是:

  1. from openpyxl.cell.cell import Cell, MergedCell

  2. row_text_list =
  3. for row in sheet_object.rows:
  4.     for cell in row:
  5.         # 如果是普通单元格且有值
  6.         if isinstance(cell, Cell) and not isinstance(cell, MergedCell) and cell.value is not None:
  7.             row_text_list.append(cell.value)
  8.         # 如果是合并单元格且是左上角的单元格(有值)
  9.         elif isinstance(cell, Cell) and cell.value is not None:
  10.             # 这里需要额外检查是否为合并单元格的左上角
  11.             # 或者直接添加
  12.             row_text_list.append(cell.value)
复制代码


不过对于你的需求(不含None和"-"),你的代码已经满足了!推导式确实可以不需要了。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2026-1-20 17:06

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表