Skip to main content

Numbers and "numbers" in Python

| 10.06.2022

Numbers and numbers in Python

Did you know that Python has three base number types?

  • integers
  • floats
  • complex numbers

If you're new to Python, but used to Engineering, this may come as a bit of surprise, but a welcome one. For those of you that are the reverse, complex numbers are incredibly commonly used in engineering; you can do some really cool stuff with them. In Python they look like this.

In [1]: a = 1 - 4j

In [2]: type(a)
Out[2]: complex

In [3]: a.imag
Out[3]: -4.0

In [4]: a.real
Out[4]: 1.0

In [5]: a.conjugate()
Out[5]: (1+4j)

In [6]:

Pretty neat! You can also access a lot of complex number operations via the built-in library cmath, but that's a topic for another time.

You can actually access quite a lot of additional types of number from commonly used packages, but particularly from numpy specifically, which provides things like numpy.int64: a signed, 64-bit integer. Types like this are commonly built-in in older languages more oriented toward number crunching, with FORTRAN perhaps being the most obvious example (if ever there was a language made for working with numbers it was FORTRAN). However, I assume Python eschewed them in favour of accessibility. Python is about being accessible and readable, so there are just 3 base numerical types and one of those is fairly uncommon (complex numbers).

OK, great, but when are you going to talk about numbers?

Well, the important part of the preamble is to establish that Python does have a lot of numerical types, despite appearances. Many of those are available through numpy, but this is Ansys, the engineering software company. Numerical computation is what we do. So we often end up working with them, a lot. But Python is also a dynamically typed language and one that is particularly relaxed when it comes to numbers.

In [7]: 1 + 1.0
Out[7]: 2.0

In [8]: 2.0 + (3+5j)
Out[8]: (5+5j)

In [9]: 6/(5+8j)
Out[9]: (0.33707865168539325-0.5393258426966292j)

In [10]: 7./14
Out[10]: 0.5

In [11]: 14/7.
Out[11]: 2.0

In [12]:

It will happily let you change the numerical type of a variable in your program's execution, and it probably won't even cause any problems (in your code). However, this doesn't mean problems aren't caused... For example, when working with data it is not uncommon to come across mis-entered data or corrupted information, and get things like NaNs ("not a number") when attempting to parse something that's not quite right.

In [12]: float('nan')
Out[12]: nan

In [13]:

NaNs are tricky beasts to work with and I won't dwell on them here, but you should check out this post by Julia Di Rosso if you want to know more.

And at some point as a developer you will hit this problem.

"How do I check if my variable is a number?"

That's where numbers comes in. This is a builtin-library of numeric abstract base classes (or "ABCs").

If you know what that means, great! If you don't then the quick summary is that its a collection of classes that are not intended to ever be instantiated. Instead, they are to be inherited from, with built-in methods that can be overwritten or made use of in other ways. Python has a built-in library for building your own or otherwise working with them called abc

In particular numbers has a variety of numeric ABCs but the most general one, is Number. This is how you solve the posed problem. We can use it in conjunction with isinstance to check if anything we pass to it is a numeric value!

In [1]: import numpy as np

In [2]: from numbers import Number

In [3]: for i in [1, 1., -0.2, 1e8, np.int64(1), np.int0(10), np.int16(2), np.float64(10), np.complex64(10), np.int32(89)]:
   ...:     print(isinstance(i, Number))
   ...:
True
True
True
True
True
True
True
True
True
True

isinstance(a, b) is a simple built-in that checks if the first provided argument a is an instantiated instance of the second b. Generally, it should be avoided as it is considered a code "smell".

Code "smells" are features of a program that suggest an underlying issue, but aren't necessarily bad in and of themselves. isinstance is a good example because the function isn't bad but it is commonly misused, so seeing it appear in a program could be a sign that something elsewhere is wrong. If you find yourself using it a lot you should take a closer look at your code and work out why!

Conclusion

As explained above, you should avoid using isinstance in long programs generally. However, when debugging or scripting, which we, as developers, probably do more than anything else, this is an invaluable tool to have at your disposal. It's another tool for the box.