2011-09-01 10 views
8

को छोड़कर एक प्रयास में व्यक्तिगत विवरणों को लपेटने के लिए पायथन साफ ​​तरीका मैं वर्तमान में कॉम के साथ एक्सेल के कुछ पायथन स्वचालन कर रहा हूं। यह पूरी तरह कार्यात्मक है, और जो मैं चाहता हूं वह करता है, लेकिन मुझे कुछ आश्चर्य की बात है। कभी-कभी, मेरे द्वारा उपयोग किए जाने वाले कुछ एक्सेल कमांड किसी स्पष्ट कारण के लिए अपवाद के साथ विफल हो जाएंगे। अन्य बार, वे काम करेंगे।ब्लॉक

मैं जो कर रहा हूं उसके लिए वीबी समकक्ष कोड में, यह समस्या स्पष्ट रूप से सामान्य मानी जाती है, और On Error Resume Next कथन के साथ plastered है। पाइथन ने निश्चित रूप से बयान नहीं कहा है।

मैं पूरे सेट को try except लूप में लपेट नहीं सकता, क्योंकि यह आधा रास्ते "विफल" हो सकता है और ठीक से पूरा नहीं हो सकता है। तो, ब्लॉक को छोड़कर एक कोशिश में कई स्वतंत्र बयान लपेटने के लिए एक पाइथोनिक तरीका क्या होगा? विशेष रूप से, कुछ क्लीनर की तुलना में:

try: 
    statement 
except: 
    pass 
try: 
    statement 
except: 
    pass 

प्रासंगिक कोड 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 

अद्यतन:

शायद त्रुटि बिट पर स्पष्टीकरण का एक सा की आवश्यकता है। एक ही फाइल पर, समान कोड के साथ, मेरी टेस्ट मशीन पर दो समान रन, एक ही परिणाम उत्पन्न करते हैं। एक रन प्रत्येक xlInsideVertical लाइन के लिए अपवाद फेंकता है। दूसरा xlInsideHorizontal के लिए अपवाद फेंकता है। अंत में, एक तीसरा रन बिल्कुल अपवाद के साथ पूरा करता है।

जहाँ तक मैं बता सकता हूं एक्सेल इस सामान्य व्यवहार को मानता है, क्योंकि मैं एक्सेल के मैक्रो जनरेटर द्वारा निर्मित वीबी कोड क्लोन कर रहा हूं, किसी व्यक्ति द्वारा उत्पादित वीबी कोड नहीं। यह निश्चित रूप से एक गलत धारणा हो सकती है।

यह ब्लॉक को छोड़कर एक कोशिश में लिपटे प्रत्येक पंक्ति के साथ काम करेगा, मैं बस कुछ छोटा और अधिक स्पष्ट चाहता था, क्योंकि 20 लाइनों को अपने स्वयं के प्रयास में लपेटकर पकड़ने की लूप बस बाद में परेशानी के लिए पूछ रही है।

Update2:

इस परीक्षण के लिए एक झाड़ी CSV फ़ाइल है: gist file

निष्कर्ष:

Vsekhar द्वारा प्रदान की जवाब एकदम सही है। यह अपवाद दमन को दूर करता है, ताकि बाद में, यदि मेरे पास समय हो, तो मैं वास्तव में अपवादों के साथ व्यवहार कर सकता हूं। यह अपवादों को लॉगिंग करने की भी अनुमति देता है ताकि वे गायब न हों, अन्य अपवाद को रोक नहीं रहा है, और अब से छह महीने आसानी से प्रबंधित करने के लिए पर्याप्त छोटा है।

+1

इसे पहली जगह में असफल होने के बारे में कैसे? पाइथन PHP या विजुअल बेसिक नहीं है और दुर्भाग्यवश यह सिन त्रुटि प्रबंधन को लागू करता है :( –

+0

क्या आप सभी कॉलों को सूची में सहेज सकते हैं और फिर लूप में एकल प्रयास कथन के साथ उन पर फिर से सक्रिय हो सकते हैं? बस यह नहीं जानना कि इसे कैसे "सहेजना" कॉल की तरह। – rplnt

+0

@ आरपीआईएनटी: कथन पाइथन में प्रथम श्रेणी की वस्तुएं नहीं हैं - उन्हें चर के लिए असाइन नहीं किया जा सकता है और कार्यों में पारित किया जा सकता है –

उत्तर

12

सार संक्षेप पर विचार करें दमन दूर करो। और हारून के बिंदु पर, आम तौर पर अपवादों को निगलो मत।

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('...') 
फिर

, अपने वर्तमान कोड के ट्रैस बैक वास्तव में क्या अपवाद उठाया है में टिप्पणी है, और सिर्फ इतना है कि अपवाद के लिए एक शमन बनाने के लिए: (

s = Suppressor(excel.WhateverError) # TODO: put your exception type here 
s('excel.Selection.Borders(xlDiagonalDown).LineStyle = xlNone') 

इस तरह आप पंक्ति-दर-पंक्ति निष्पादन प्राप्त इसलिए आपके ट्रेसबैक अभी भी सहायक होंगे), और आप केवल उन अपवादों को दबाने वाले हैं जिन्हें आप स्पष्ट रूप से लक्षित करते हैं। अन्य अपवाद सामान्य रूप से प्रचारित करते हैं।

+0

यह हारून डिगुल्ला का सुझाव देने की भावना में बहुत अधिक है, सिवाय इसके कि आप * नामित * अपवादों को चुपचाप * निगल रहे हैं। आप डिफ़ॉल्ट रूप से * अपवाद को अपवादित करने के लिए वास्तव में सही हैं, लेकिन आईएमओ कम से कम उन अपवादों को लॉग इन करना बेहतर होगा जिन्हें आप दबाते हैं, या उन्हें डेटा संरचना में संग्रहीत करते हैं जिसे प्रोग्राम निष्पादन के अंत में डंप किया जा सकता है ताकि आप देख सकते हैं कि वास्तव में क्या हुआ। – Peter

+1

@ पीटर: काफी मेला, मैंने लॉगिंग व्यवहार जोड़ा – vsekhar

10

अपवाद कभी भी "किसी स्पष्ट कारण के लिए" नहीं होता है। हमेशा एक कारण होता है और उस कारण को ठीक करने की आवश्यकता होती है। अन्यथा, आपका प्रोग्राम "यादृच्छिक" डेटा उत्पन्न करना शुरू कर देगा जहां आप छिपे हुए बग की दया पर "यादृच्छिक" है।

लेकिन निश्चित रूप से, आपको अपनी समस्या का समाधान चाहिए। यहां मेरा सुझाव दिया गया है:

  1. एक रैपर वर्ग बनाएं जो आपको आवश्यक सभी विधियों को लागू करता है और उन्हें वास्तविक एक्सेल उदाहरण में प्रतिनिधि करता है।

  2. प्रत्येक विधि से पहले एक सजावट जोड़ें जो try except ब्लॉक में विधि को लपेटता है और अपवाद लॉग करता है। कभी अपवाद

निगल अब कोड अपने ग्राहक जो आप कुछ समय समस्या का कारण पता लगाने के लिए खरीदता है के लिए काम करता है। मेरा अनुमान है कि ए) एक्सेल एक उपयोगी त्रुटि संदेश उत्पन्न नहीं करता है या बी) रैपर कोड आपको अंधेरे में छोड़ने वाले वास्तविक अपवाद को निगलता है या सी) एक्सेल विधि एक त्रुटि कोड देता है (जैसे "असफल" के लिए "झूठा") और समस्या का कारण क्या है यह निर्धारित करने के लिए आपको एक और एक्सेल विधि कॉल करने की आवश्यकता है।

[संपादित करें] टिप्पणी जो नीचे करने के लिए नीचे उबाल "मेरे मालिक की परवाह नहीं करता और कुछ भी नहीं मैं कुछ नहीं कर सकता है" के आधार पर: आप एक महत्वपूर्ण बिंदु छूट रहा है: यह अपने मालिकों कर्तव्य बनाने के लिए है निर्णय लेकिन आपकी कर्तव्य है कि वह पेशेवरों/विपक्ष के साथ विकल्पों की एक सूची दे ताकि वह एक अच्छा निर्णय ले सके। वहां बस बैठकर "मैं कुछ भी नहीं कर सकता" आपको उस परेशानी में लाएगा जिसे आप टालने की कोशिश कर रहे हैं।

उदाहरण:

समाधान 1: पर ध्यान न दें त्रुटियों

प्रो: काम के कम से कम राशि कोन: संभव है परिणामी डेटा गलत या यादृच्छिक है। यदि महत्वपूर्ण व्यावसायिक निर्णय इस पर आधारित हैं, तो एक उच्च जोखिम है कि ये निर्णय गलत होंगे।

समाधान 2: के लिए लॉग इन त्रुटियों

प्रो: काम की छोटी राशि, उपयोगकर्ताओं, जल्दी से परिणाम का उपयोग करने के लिए शुरू कर सकते हैं समस्या कोन का स्रोत पता लगाने की समय खरीदता है: "आप ठीक नहीं कर सकते हैं आज, आपको क्या लगता है कि कल आपके पास इसे ठीक करने का समय होगा? " इसके अलावा, यह आप एक लंबा समय लग सकता समस्या के स्रोत खोजने के लिए है क्योंकि आप कोई विशेषज्ञ

समाधान 3 कर रहे हैं: एक विशेषज्ञ

पूछें क्षेत्र में महारत का पता लगाएं और उसकी मदद/उसे एक नजर है/समाधान में सुधार।

प्रो: अपने आप को COM के अंदर और बहिष्कार सीखने से अधिक समाधान मिलेगा कॉन: महंगी लेकिन सफलता का उच्च अवसर। उन समस्याओं को भी मिलेगा जिन्हें हम नहीं जानते हैं।

...

मैं तुम्हें पैटर्न को देखने लगता है। मालिक गलत निर्णय लेते हैं क्योंकि हम (स्वेच्छा से) उन्हें देते हैं। दुनिया में कोई भी मालिक कठिन तथ्यों और इनपुट के लिए खुश होता है जब उन्हें निर्णय लेना पड़ता है (ठीक है, जो मालिक नहीं होना चाहिए, इसलिए यह जानना एक निश्चित तरीका है कि एक नई नौकरी की तलाश शुरू करने के लिए कब) ।

यदि आप समाधान # 2 का चयन करते हैं, तो रैपर दृष्टिकोण के लिए जाएं। See the docs एक सजावट कैसे लिखना है (example from IBM)। यह सभी विधियों को लपेटने के लिए बस कुछ ही मिनटों का काम है और यह आपको काम करने के लिए कुछ देगा।

अगला चरण एक छोटा उदाहरण बनाना है जो कभी-कभी विफल रहता है और फिर समस्याओं के कारण को जानने के लिए यहां पाइथन, एक्सेल और COM wrapper के बारे में विशिष्ट प्रश्न पोस्ट करता है।

[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 

उपयोग:

borders = BorderHelper(excel) 

    borders.set(xlDiagonalDown, LineStyle = xlNone) 
    borders.set(xlDiagonalUp, LineStyle = xlNone) 
    borders.set(xlEdgeLeft, LineStyle = xlContinuous, Weight = xlThin, Color = xlAutomatic) 
    ... 
+4

मुझे लगता है कि शब्द का मतलब यह नहीं है कि इसका क्या अर्थ है। हमेशा एक कारण होता है, यह अक्सर "स्पष्ट" नहीं होता है। – agf

+0

मुझे अज्ञानता के लिए मेरी अवमानना ​​व्यक्त करने के लिए एक बेहतर शब्द नहीं मिला :-) –

+0

@Aaron Digulla मैंने थोड़ा और पृष्ठभूमि जानकारी के साथ अपना प्रश्न अपडेट किया है। यदि आप इस मुद्दे पर प्रकाश डालने के लिए एक्सेल और कॉम प्रोग्रामिंग के बारे में पर्याप्त जानते हैं तो मैं आभारी रहूंगा। लेकिन मेरे मामले में, कॉम पर पढ़ने के 20 मिनट, और पाइथन कॉम उदाहरण पढ़ने में 15 मिनट बस इसे डीबग करने के लिए पर्याप्त समस्या स्थान को कवर नहीं करते हैं। एमएनटीटी एक दिन में चाहता है, न कि मैं कॉम सीखने और एक्सेल डीबग करने के बाद। –

4

यह सिर्फ फ़ंक्शन कॉल को लपेटता है, लेकिन आप इसे एट्रिब्यूट एक्सेस को संभालने के लिए और नेस्टेड विशेषता एक्सेस के परिणामों को प्रॉक्सी करने के लिए बढ़ा सकते हैं, अंत में ब्लॉक में __setattr__ को लपेटें।

आपके मामले में केवल कुछ विशिष्ट अपवाद प्रकारों को निगलना समझदार हो सकता है (जैसा कि @ वीशेखर कहते हैं)।

def onErrorResumeNext(wrapped): 
    class Proxy(object): 
     def __init__(self, fn): 
      self.__fn = fn 

     def __call__(self, *args, **kwargs): 
      try: 
       return self.__fn(*args, **kwargs) 
      except: 
       print "swallowed exception" 

    class VBWrapper(object): 
     def __init__(self, wrapped): 
      self.wrapped = wrapped 

     def __getattr__(self, name): 
      return Proxy(eval('self.wrapped.'+name)) 

    return VBWrapper(wrapped) 

उदाहरण:

exceptionProofBorders = onErrorResumeNext(excel.Selection.Borders) 
exceptionProofBorders(xlDiagonalDown).LineStyle = xlNone 
exceptionProofBorders(xlDiagonalup).LineStyle = xlNone 
0

आप तीन सूची से तर्क ज़िप सकते हैं, और निम्न कार्य करें:

for border, attr, value in myArgs: 
    while True: 
     i = 0 
     try: 
      setattr(excel.Selection.Borders(border), attr, value) 
     except: 
      if i>100: 
       break 
     else: 
      break 

अपने अपवाद trully यादृच्छिक कर रहे हैं, इस सफलता तक कोशिश करेंगे (साथ 100 कोशिशों की एक सीमा)। मैं इसकी सिफारिश नहीं करता हूं।