Spe*_*bun 8 python com excel vba try-catch
我目前正在使用com进行Excel的Python自动化.它功能齐全,可以满足我的需求,但我发现了一些令人惊讶的东西.有时,我使用的某些Excel命令会因为没有明显原因的异常而失败.其他时候,他们会工作.
在我正在做的VB等效代码中,这个问题显然被认为是正常的,并且用一个On Error Resume Next语句贴满了.当然,Python没有声明.
我无法将整个集合包裹在一个try except循环中,因为它可能会在中途"失败"并且无法正常完成.那么,将几个独立语句包装到try除块之外的pythonic方法是什么?具体来说,比以下更清洁:
try:
statement
except:
pass
try:
statement
except:
pass
Run Code Online (Sandbox Code Playgroud)
相关的代码是excel.Selection.Borders位.
def addGridlines(self, infile, outfile):
"""convert csv to excel, and add gridlines"""
# set constants for excel
xlDiagonalDown = 5
xlDiagonalUp = 6
xlNone = -4142
xlContinuous = 1
xlThin = 2
xlAutomatic = -4105
xlEdgeLeft = 7
xlEdgeTop = 8
xlEdgeBottom = 9
xlEdgeRight = 10
xlInsideVertical = 11
xlInsideHorizontal = 12
# open file
excel = win32com.client.Dispatch('Excel.Application')
workbook = excel.Workbooks.Open(infile)
worksheet = workbook.Worksheets(1)
# select all cells
worksheet.Range("A1").CurrentRegion.Select()
# add gridlines, sometimes some of these fail, so we have to wrap each in a try catch block
excel.Selection.Borders(xlDiagonalDown).LineStyle = xlNone
excel.Selection.Borders(xlDiagonalUp).LineStyle = xlNone
excel.Selection.Borders(xlDiagonalUp).LineStyle = xlNone
excel.Selection.Borders(xlEdgeLeft).LineStyle = xlContinuous
excel.Selection.Borders(xlEdgeLeft).Weight = xlThin
excel.Selection.Borders(xlEdgeLeft).ColorIndex = xlAutomatic
excel.Selection.Borders(xlEdgeTop).LineStyle = xlContinuous
excel.Selection.Borders(xlEdgeTop).Weight = xlThin
excel.Selection.Borders(xlEdgeTop).ColorIndex = xlAutomatic
excel.Selection.Borders(xlEdgeBottom).LineStyle = xlContinuous
excel.Selection.Borders(xlEdgeBottom).Weight = xlThin
excel.Selection.Borders(xlEdgeBottom).ColorIndex = xlAutomatic
excel.Selection.Borders(xlEdgeRight).LineStyle = xlContinuous
excel.Selection.Borders(xlEdgeRight).Weight = xlThin
excel.Selection.Borders(xlEdgeRight).ColorIndex = xlAutomatic
excel.Selection.Borders(xlInsideVertical).LineStyle = xlContinuous
excel.Selection.Borders(xlInsideVertical).Weight = xlThin
excel.Selection.Borders(xlInsideVertical).ColorIndex = xlAutomatic
excel.Selection.Borders(xlInsideHorizontal).LineStyle = xlContinuous
excel.Selection.Borders(xlInsideHorizontal).Weight = xlThin
excel.Selection.Borders(xlInsideHorizontal).ColorIndex = xlAutomatic
# refit data into columns
excel.Cells.Select()
excel.Cells.EntireColumn.AutoFit()
# save new file in excel format
workbook.SaveAs(outfile, FileFormat=1)
workbook.Close(False)
excel.Quit()
del excel
Run Code Online (Sandbox Code Playgroud)
更新:
也许需要对错误位进行一些解释.我的测试机器上的两个相同的运行,在相同的文件上具有相同的代码,产生相同的结果.一次运行会抛出每xlInsideVertical行的异常.另一个抛出异常xlInsideHorizontal.最后,第三次运行完成,完全没有例外.
据我所知,Excel会考虑这种正常行为,因为我正在克隆由excel的宏生成器构建的VB代码,而不是由人生成的VB代码.当然,这可能是一个错误的假设.
它将在try中包含的每一行中起作用,除了块我只想要更短更明显的东西,因为在他们自己的try catch循环中包含的20行只是后来要求麻烦.
Update2:
这是一个用于测试的清理CSV文件:gist文件
结论:
Vsekhar提供的答案是完美的.它抽象了异常抑制,以便以后,如果我有时间,我实际上可以处理它们发生的异常.它还允许记录异常,以便它们不会消失,不会停止其他异常,并且足够小,可以在六个月后轻松管理.
vse*_*har 12
考虑抽象压制.而对于Aaron来说,一般不要吞下异常.
class Suppressor:
def __init__(self, exception_type):
self._exception_type = exception_type
def __call__(self, expression):
try:
exec expression
except self._exception_type as e:
print 'Suppressor: suppressed exception %s with content \'%s\'' % (type(self._exception_type), e)
# or log.msg('...')
Run Code Online (Sandbox Code Playgroud)
然后,在当前代码的回溯中注意确切引发的异常,并为该异常创建一个Suppressor:
s = Suppressor(excel.WhateverError) # TODO: put your exception type here
s('excel.Selection.Borders(xlDiagonalDown).LineStyle = xlNone')
Run Code Online (Sandbox Code Playgroud)
这样您就可以逐行执行(因此您的回溯仍然有用),并且您只能抑制明确指定的异常.其他例外照常传播.
Aar*_*lla 10
例外永远不会"无缘无故"地发生.总有一个原因,需要修复这个原因.否则,您的程序将开始生成"随机"数据,其中"随机"受您隐藏的错误的支配.
但是,当然,您需要一个解决方案来解决您的问题.这是我的建议:
创建一个包装器类,实现您需要的所有方法,并将它们委托给真正的Excel实例.
在每个方法之前添加一个装饰器,将方法包装在一个try except块中并记录异常.永远不要吞下例外
现在代码适用于您的客户,它会花一些时间来找出问题的原因.我的猜测是a)Excel不会产生有用的错误信息或b)包装器代码吞下真正的异常,让你在黑暗中或c)Excel方法返回错误代码(如"失败"的"假")并且您需要调用另一个Excel方法来确定问题的原因.
[编辑]根据下面的评论归结为"我的老板不关心,我无能为力":你错过了一个关键点:做出决定是你的老板的责任,但你有责任给予她列出了选项以及优点/缺点,以便她做出明智的决定.只是坐在那里说"我什么都做不了"会让你陷入你想要避免的麻烦之中.
例:
Pro:工作量最少Con:结果数据有可能是错误的或随机的.如果重要的业务决策是基于它的,那么这些决策很有可能是错误的.
专业:工作量少,用户可以快速开始使用结果,花时间找出问题的根源Con:"如果你今天无法解决问题,那么你认为明天你有时间修复它的原因是什么?" 此外,您可能需要很长时间才能找到问题的根源,因为您不是专家
找一位该领域的专家,帮助他/她看看/改进解决方案.
亲:比自己学习COM的来龙去快得多解决方案Con:昂贵但成功的机率很高.还会发现我们甚至不知道的问题.
...
我想你看到的模式.老板做出错误的决定,因为我们(心甘情愿地)让他们.当他们必须作出决定时,世界上的任何老板都对于事实和投入感到高兴(好吧,那些不应该是老板的人,所以这是一种确定何时开始寻找新工作的绝对方式) .
如果选择解决方案#2,请选择包装器方法.请参阅docs如何编写装饰器(来自IBM的示例).包装所有方法只需几分钟的工作,它将为您提供一些工作.
下一步是创建一个较小的示例,有时会失败,然后在此处发布有关Python,Excel和COM包装器的特定问题,以找出问题的原因.
[EDIT2]下面是一些代码,它们将帮助类中的"危险"部分包装起来,并使更新样式更加简单:
class BorderHelper(object):
def __init__(self, excel):
self.excel = excel
def set( type, LineStyle = None, Weight = None, Color = None ):
border = self.excel.Selection.Borders( type )
try:
if LineStyle is not None:
border.LineStyle = LineStyle
except:
pass # Ignore if a style can't be set
try:
if Weight is not None:
border.Weight = Weight
except:
pass # Ignore if a style can't be set
try:
if Color is not None:
border.Color = Color
except:
pass # Ignore if a style can't be set
Run Code Online (Sandbox Code Playgroud)
用法:
borders = BorderHelper( excel )
borders.set( xlDiagonalDown, LineStyle = xlNone )
borders.set( xlDiagonalUp, LineStyle = xlNone )
borders.set( xlEdgeLeft, LineStyle = xlContinuous, Weight = xlThin, Color = xlAutomatic )
...
Run Code Online (Sandbox Code Playgroud)