scalar vs array and program control

Laura Creighton lac at openend.se
Sat Jul 25 13:01:21 CEST 2015


You have a bit of a problem, in that "functional" and "object-oriented"
are two different styles of programming.  You really cannot make your
code 'more functional' and 'more object-oriented' at the same time --
more in one style implies less in the other.  I think you may have
got the mistaken idea that 'object-orientated' means 'well-written'
or 'professional' or some such.

However, if your intuition was telling you that it would be bad to
write code that goes:

if type(x) is str:
   do_something()
elif type(x) is float:
   do_something_else()
elif type(x) is int:
   do_another_thing()
else:
   scream_loudly_and_dont_do_anything()

then your intuition is working perfectly.  Don't stick typechecks in all
over your code.  It makes it fragile and hard to maintain.  It also means
that you have to anticipate all the perfectly good input you might have,
and nobody can do that.

For instance, might somebody want to feed your functions complex numbers
one day?  Or, here is a good one -- python has a Decimal datatype
which does Decimal floating point arithmetic.  You don't want your code
to not work for people using Decimal numbers just because you didn't
put in a check for
>>> type(Decimal(10.5))
<class 'decimal.Decimal'>

If you find you need to check the type of something, it is better to use
the isinstance function.

if isinstance(x, str):
   do something()
else:
   do_something_else()

The python builtin types are all included here.  For the sort of work
you do it is useful to know about

from numbers import Number
     isinstance(x, Number)

which will happily return True for all sorts of numbers, complex,
Decimal numbers even number classes which you define yourself.

So if you need to do this sort of 'look before you leap' checking,
isinstance is the way to do it.  And sometimes this _is_ the sort of
checking you want to do.  But, aside from when you are writing test
code, where it happens all over the place, most of the type in writing
Python code we don't do this either.

We don't look before we leap.  We leap, and then if there are any
problems, we deal with it.

Instead we do something like this:

consider a function that converts a string to a number

def string_to_number(s):
   try:
      return int(s)
   except ValueError:
      return float(s)

If all your input is guaranteed to be ints or floats this will work fine.
It also works if you feed it things that are already ints and floats
(not strings).  And this is nice .

How did I know to look for ValueErrors?

>>> int("1.2")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ValueError: invalid literal for int() with base 10: '1.2'

Cause that is what Python gives you.  If it had given you a TypeError
instead -- which is what I expected it to do, but so it goes -- I
would have said except TypeError.

You can stack these things.

>>>
def string_to_number(x):
   try:
     return int(x)
   except ValueError:
      try:
         return float(x)
      except ValueError:
         return complex(x)

So now it handles complex numbers as well.

So this is, quite likely, the pattern that you are looking for:

try:
	all_your_code_which_is_happy_with_non_scalars
except WhateverErrorPythonGivesYouWhenYouTryThisWithScalars:
       whatever_you_want_to_do_when_this_happens

This is the usual way to do things.

If you find that your try/except pairs are walking themselves all the
way to the right hand side of the screen it is time to consider
restructuring your code.

The great advantage of this approach is that you don't have to
pretend to omniscience about the sort of input you will get.  If I
decide to call your code with an array of Decimal floating point
integers instead of regular floats, it's great if it just works,
whether or not you had the idea of Decimal floating point in mind
when you wrote the code.

Sorry to be so longwinded.  I need to go now and don't have time to
revise it, though it probably should be made a whole bunch less
preachy.

Hope it helps,
Laura






  




More information about the Python-list mailing list