4

I want all mathematical operations involving one or more None variables to return None.

Example:

a = None
b = 7
a*b 

I want this last line to return None, but it instead gives me an error:

TypeError: unsupported operand type(s) for *: 'NoneType' and 'int'

I understand why this error exists and all that, but is there any way to force the result to be just a None?

Background: I have a few functions that mine data and return a value, called diff. Later on I multiply or add diff to a few things to get meaningful information, but not all of my original data contains a useful diff, so I have it set to return diff = None in these cases. I want to be able to skip over these points when I'm plotting results. Python seems to have no trouble skipping over None elements in an array when I'm plotting, so I'd like to just have the results of the operations be None.

Tonechas
  • 13,398
  • 16
  • 46
  • 80
barriboy
  • 151
  • 1
  • 7
  • 3
    Use a float("NaN") rather than `None` – donkopotamus Jul 25 '16 at 22:43
  • 1
    [How to chain attribute lookups that might return None?](http://stackoverflow.com/q/15280511); [Maybe "kind of" monad in python](http://stackoverflow.com/q/8507200), – jscs Jul 25 '16 at 22:45
  • Similar to @donkopotamus you can use the decimal module and `decimal.Decimal('NaN')` for `None`. This may be preferable if you want correctly-rounded decimal arithmetic. If all of your operations use `Decimal` numbers it will work the way you want. – tdelaney Jul 25 '16 at 22:49

3 Answers3

10

Instead of trying to force all mathematical operations that contain some arbitrary other value to return that arbitrary other value, you could simply use a NaN, which is designed for exactly this sort of purpose:

>>> nan = float("NaN")
>>> 7 * nan
nan
>>> 7 + nan
nan

A nan will correctly cascade throughout your mathematical operations.

A good plotting library will also understand nan and omit them at plot time. But if not, simply do your replacement of NaN to None immediately prior to plotting.

donkopotamus
  • 22,114
  • 2
  • 48
  • 60
0

You can check for presence of None in arguments and then return early:

def calc(*args, **kwargs):
    if None in list(args) + list(kwargs.keys()):
        return None
    #rest

You can also write a decorator and wrap the existing functions, this would be more useful if you want to apply this operation to many existing functions (or even just one, for clarity):

def return_none_for_none(f):
    def wrapped(*args, **kwargs):
        return None if None in list(args) + list(kwargs.keys()) else f(*args, **kwargs)
    return wrapped


@return_none_for_none
def some_math_exp(a, b, c=2):
    return a + b*c
DurgaDatta
  • 3,952
  • 4
  • 27
  • 34
0

Without having much context to your code structure; I assume you just want to try an operation, and return None if it's not possible.

Perhaps a try/except could work here:

try:
    # operation here
except TypeError:
    return None

However I do agree with @donkopotamus using a NaN float value accomplishes exactly what you're looking for. If the expression you're try to evaluate contains a NaN then the entire expressions evaluates to NaN. You could always return None if NaN is found, or convert your data when passing it to the math library.

>>> nan = float('NaN')
>>> nan + 15 ** 4
nan
>>> 1000 - nan /6%3
nan
>>> 
ospahiu
  • 3,465
  • 2
  • 13
  • 24
  • Being pedantic, a `nan` will not always cause a parent expression to evaluate to `nan`. Consider `1**nan` or `nan**1`. All these rules for cascade have been carefully thought of by others, we need not second guess ;-) – donkopotamus Jul 25 '16 at 23:03