Python xlrd 命名范围值
在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 个回答
最初的问题和例子已经被@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)
首先,关于这个名字,它是小写的,这在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'