try..except or type() or isinstance()?

Manfred Lotz ml_news at posteo.de
Sat Aug 15 04:14:58 EDT 2020


Hi Chris,
Thanks a lot for you advice.

On Sat, 15 Aug 2020 16:15:29 +1000
Chris Angelico <rosuav at gmail.com> wrote:

> On Sat, Aug 15, 2020 at 3:36 PM Manfred Lotz <ml_news at posteo.de>
> wrote:
> >
> > I have an object which I could initialize providind an int or a str.
> >
> > I am not sure which of the following is best to use
> >  - try/except
> >  - if type(int)...
> >  - if isinstance(v, int)
> >
> > Here a minimal example
> >
> > def get_id(fromname):
> >     # do something with `fromname`
> >     return 0
> >
> > def get_name(fromid):
> >     # do something with `fromid`
> >     return "something"
> >
> > """ For O1, O2, O3: self.myid is int
> >                                         self.name is str
> > """
> > class O1:
> >     def __init__(self, val):
> >         try:
> >             self.myid = int(val)
> >             self.name = get_name(self.myid)
> >         except:
> >             self.myid = get_id(val)
> >             self.name = val  
> 
> Don't use a bare "except" - use "except ValueError" instead. 

Oops, yes. You are right, of course.

> But
> otherwise, this is a perfectly reasonable way to say "anything that
> can be interpreted as an integer will be".
> 
> > class O2:
> >     def __init__(self, val):
> >         if type(val) == int:
> >             self.myid = val
> >             self.name = get_name(self.myid)
> >         else:
> >             self.myid = get_id(val)
> >             self.name = val  
> 
> Nope, don't do this. It's strictly worse than O3.
> 

Aaa ok. I think in this particular case it would be ok but in general
it might be bad if val would be a class object. 

So, I take your advice to avoid this in general as then I avoid errors
in more complicated situations when using type(..).


> > class O3:
> >     def __init__(self, val):
> >         if isinstance(val, int):
> >             self.myid = val
> >             self.name = get_name(self.myid)
> >         else:
> >             self.myid = get_id(val)
> >             self.name = val  
> 
> This is a perfectly reasonable way to say "integers will be treated as
> IDs". Note that O1 and O3 are very different semantically; O1 will
> treat the string "7" as an ID, but O3 will treat it as a name.
> 
> Here's an even better way:
> 
> class O4:
>     def __init__(self, id):
>         self.myid = id
>         self.name = get_name(id)
>     @classmethod
>     def from_name(cls, name):
>         return cls(get_id(name))
> 

> This makes the ID the main way you'd do things, and a name lookup as
> an alternate constructor. Very good pattern, reliable, easy to use.
> 

For my use case I don't like this solution as I get the value which
could be an int or str from a file. Means I would have to check the
type beforehand in order to know if I have to do O4(val) or
O4.from_name(val).

Otherwise, it is admittedly a very good pattern.


-- 
Manfred




More information about the Python-list mailing list