Python xlrd 命名范围值

4 投票
2 回答
8055 浏览
提问于 2025-04-18 11:13

在Python中使用XLRD来读取Excel文件。

这是一个简单的场景。我有一个单元格,它里面有一个值,并且这个值与一个命名范围有关。

命名范围 "Foo" = Sheet1!$A$1 在A1单元格里的值是 "Bar"

book =xlrd.open_workbook("")

rng =  book.name_map['foo'][0]  # lower case for some reason.

print rng.???   # how to print the cell value bar??

我只想在Python代码中引用这个命名范围 "Foo",然后打印出单元格里的值 "Bar"。

编辑: 这里有一个更完整的例子:

import xlrd

workbook = xlrd.open_workbook('/path/to/metester.xls')
cell_obj = workbook.name_and_scope_map.get(('sales', -1))
# this does print Sheet1!$A$1
print cell_obj.formula_text
# this raises the NoneTypeError
print cell_obj.cell()

formula_text是为了确保Excel能读取这个文件。在我的例子中,命名单元格是 "sales",位于Sheet1的A1单元格。

返回:

Sheet1!$A$1
Traceback (most recent call last):
  File "tester.py", line 7, in <module>
    print cell_obj.cell()
  File "/usr/local/lib/python2.7/dist-packages/xlrd/book.py", line 253, in cell
    self.dump(self.book.logfile,
AttributeError: 'NoneType' object has no attribute 'logfile'

2 个回答

3

最初的问题和例子已经被@jonnybazookatone的回答完美解答了。扩展的例子则是另一个错误。我觉得这似乎是xlrd的一个缺陷,但我找到了一个解决你需求的方法。第一部分是解释,最后一部分是解决方案。

解释

看一下更详细的例子,错误信息是由这段代码产生的,它处理了Name对象的错误情况,原因是计算Name范围内的公式时失败了。

实际报告的错误是

AttributeError: 'NoneType' object has no attribute 'logfile'

这是一个次要错误——表示这个Name对象的self.book的值为None

其次,我觉得你缺少一个重要的细节,那就是你的Excel文件是.xlsx格式的。注意后面的x。在正常的xls解析器中,Name对象没有formula_text这个属性,所以你的代码会出现以下错误。

Traceback (most recent call last):
  File "D:\q1.py", line 16, in <module>
    print cell_obj.formula_text
AttributeError: 'Name' object has no attribute 'formula_text'

请小心你的代码示例——我花了一段时间才找到这个区别——xlsx文件是由xlrd中的完全不同的代码解析的。修复了xlsx后,我可以重现你的错误。

在这种情况下,formula_text属性只是给出了一个R-C表示法的引用,指向的是你的命名范围的单元格。需要注意的是,设置formula_text函数上面写着"#### UNDER CONSTRUCTION ####",自2012年xlsx模块首次提交以来一直如此。

问题是——据我所见——在打开一个xlsx文件时,公式从未被计算过,所以你遇到了Name.res是None的错误,因此你看到了这个错误。这似乎是xlrd的一个bug或特性。

解决方案

我想出了一个简单的解决方案,可以在你的范围是单个单元格的情况下,通过扩展单元格引用来实现你想要的功能。请注意,目前这个方法对引用多个单元格的命名范围会失败,但可以很容易地修改以应对这种情况:

hack = cell_obj.formula_text
(sheetName,ref) = hack.split('!')
(discard,colStr,rowStr) = ref.split('$')
col = 0
for i in range(len(colStr)):
    colAdd = string.ascii_uppercase.index(colStr)
    col += colAdd * 10**i
row = int(rowStr)-1
print("Trying to evaluate cell",row,col,"in sheet",sheetName)
print workbook.sheet_by_name(sheetName).cell(row,col)
5

首先,关于这个名字,它是小写的,这在xlrd模块的信息中有解释(https://secure.simplistix.co.uk/svn/xlrd/trunk/xlrd/doc/xlrd.html?p=4966):

name_map [#]

这是一个从小写名字到名称对象列表的映射。这个列表是按照作用域的顺序排列的。通常情况下,列表中会有一个项目(全局作用域)。

你有两个选择。如果你真的只是为一个单元格设置名字,那么你可以使用名称类的'cell'方法(具体可以查看文档):

import xlrd
book = xlrd.open_workbook("")
Name = book.name_map['foo'][0]
print(Name.cell())

控制台:

text:'Bar'

但是,如果你给一整片值命名了,那么你需要使用名称类的area2d方法:

import xlrd
book = xlrd.open_workbook("q1.xls")
Name = book.name_map['foo'][0]
Sheet, rowxlo, rowxhi, colxlo, colxhi = Name.area2d()
for i in range(rowxhi):
    print(Sheet.cell(i,0))

控制台:

text:'Bar'

撰写回答