how best to check a value? (if/else or try/except?)

Nick Vatamaniuc vatamane at gmail.com
Thu Jul 27 17:14:41 EDT 2006


John,

The way I do it is, is I ask myself  'is there a more common (basic)
base between the code paths or do they both have about a 50/50 chance
on average?' or 'will one code path be taken during an error and the
other one during the normal processing?'.  If there is a clear single
common/usual/basic case or I try to detect an error I use 'try/except',
if it could go either way on average I use 'if'.

In general in  Python we follow the 'it is better to ask forgiveness
than to ask permission'.  In other words if you don't know if a piece
of data you have is a function and is callable you just call it and if
it raises an exception then you'll know it's not. This is the opposite
of C where you have to spend a good deal of time validating your input
arguments before you  can safely continue.

That said, Python is also a practical language and quite often  if you
do just one check then an 'if' may take 2 lines (if no need for else)
while a try/except will take 4 lines. So just apply common sense. For
example, I want to find out if I can call f then do some stuff if that
is the case:
try:
  f(arg)
  #...do stuff because f is callable...
except TypeError:
   pass
  # ... if f is not callable, then I don't care...

But of course it is much shorter to do:
if callable(f):
   #...do stuff because f is callable...

Hope this helps,
Nick Vatamaniuc





John Salerno wrote:
> My code is below. The main focus would be on the OnStart method. I want
> to make sure that a positive integer is entered in the input box. At
> first I tried an if/else clause, then switched to try/except. Neither is
> perfect yet, but I was wondering which I should try for in the first
> place. I figure I need to check for an emptry string, non-numeric
> strings (maybe these are the same check), 0 and negative numbers (which
> might also fall into the category of 'anything but a number' because of
> the negative sign).
>
> Thanks.
>
> -------------------------------
>
> import wx
>
>
> class MyTimer(wx.Frame):
>
>      def __init__(self):
>          wx.Frame.__init__(self, None, wx.ID_ANY, 'Timer',
>                            style=wx.DEFAULT_FRAME_STYLE ^
> wx.RESIZE_BORDER ^ wx.MAXIMIZE_BOX)
>          panel = wx.Panel(self)
>
>          mainSizer = wx.BoxSizer(wx.VERTICAL)
>          inputSizer = wx.BoxSizer(wx.HORIZONTAL)
>
>          self.progress = wx.Gauge(panel, wx.ID_ANY, 100, size=(300, 20))
>          self.status = wx.StaticText(panel, wx.ID_ANY, 'Enter a time.')
>          prompt = wx.StaticText(panel, wx.ID_ANY, 'Time to wait:')
>          self.input = wx.TextCtrl(panel, wx.ID_ANY, size=(20, 20))
>          self.start = wx.Button(panel, wx.ID_ANY, 'Start')
>          self.reset = wx.Button(panel, wx.ID_ANY, 'Reset')
>          self.reset.Disable()
>          self.timer = wx.Timer(self)
>
>          mainSizer.Add(self.progress, flag=wx.ALIGN_CENTER | wx.ALL ^
> wx.BOTTOM,
>                        border=10)
>          mainSizer.Add(self.status, flag=wx.ALIGN_CENTER | wx.ALL,
> border=10)
>          mainSizer.Add(inputSizer, flag=wx.ALIGN_CENTER | wx.BOTTOM,
> border=10)
>          inputSizer.Add(prompt, flag=wx.ALIGN_CENTER)
>          inputSizer.Add(self.input, flag=wx.ALIGN_CENTER | wx.LEFT |
> wx.RIGHT,
>                         border=5)
>          inputSizer.Add(self.start, flag=wx.ALIGN_CENTER)
>          inputSizer.Add(self.reset, flag=wx.ALIGN_CENTER)
>
>          self.Bind(wx.EVT_TEXT_ENTER, self.OnStart, self.input)
>          self.Bind(wx.EVT_BUTTON, self.OnStart, self.start)
>          self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
>          self.Bind(wx.EVT_BUTTON, self.OnReset, self.reset)
>
>          panel.SetSizer(mainSizer)
>          mainSizer.Fit(self)
>
>      def OnStart(self, event):
>          try:
>              self.time = int(self.input.GetValue())
>              self.minutes_passed = 1
>              self.minutes_remaining = self.time - 1
>              self.start.Disable()
>              self.input.Disable()
>              self.reset.Enable()
>              self.status.SetLabel('%s minute(s) remaining.' % self.time)
>              self.timer.Start(1000)
>          except ValueError:
>              wx.MessageBox('Enter a valid time.', 'Invalid time entered',
>                            wx.OK | wx.ICON_ERROR)
>              self.input.Clear()
>
>      def OnReset(self, event):
>          if self.timer.IsRunning():
>              self.timer.Stop()
>          self.input.Clear()
>          self.input.Enable()
>          self.start.Enable()
>          self.reset.Disable()
>          self.status.SetLabel('Enter a new time.')
>          self.progress.SetValue(0)
>          self.minutes_passed = 1
>
>      def OnTimer(self, event):
>          if self.minutes_remaining != 0:
>              self.progress.SetValue(self.minutes_passed * (100.0 /
> self.time))
>              self.status.SetLabel('%s minute(s) remaining.' %
> self.minutes_remaining)
>              self.minutes_passed += 1
>              self.minutes_remaining -= 1
>          else:
>              self.timer.Stop()
>              self.progress.SetValue(self.minutes_passed * (100.0 /
> self.time))
>              self.status.SetLabel('%s minute(s) have elapsed.' % self.time)
>              wx.Sound.Play(wx.Sound(r'C:\Windows\Media\notify.wav'))
>
>
> class MyApp(wx.App):
>
>      def OnInit(self):
>          frame = MyTimer()
>          self.SetTopWindow(frame)
>          frame.Show()
>          return True
>
>
> if __name__ == '__main__':
>      app = MyApp(False)
>      app.MainLoop()




More information about the Python-list mailing list