feltersnach
feltersnach

Reputation: 406

How do I check an object for negative numbers

I have an object that contains the values for two differential equations.

for example:

#create equation object
class EquationValues(object):
    x         = 0
    y         = 0
    xMin      = 0
    xMax      = 0
    yMin      = 0
    yMax      = 0
    deltaTime = 0

# Class constructor/initilizer
    def __init__(self, x, y, xMin, xMax, yMin, yMax, deltaTime):
        self.x         = x
        self.y         = y
        self.xMin      = xMin
        self.xMax      = xMax
        self.yMin      = yMin
        self.yMax      = yMax
        self.deltaTime = deltaTime

def make_equationValues(x, y, xMin, xMax, yMin, yMax, deltaTime):
    equationValues = EquationValues(x, y, xMin, xMax, yMin, yMax, deltaTime)
    return equationValues

with open ('inputs.csv', 'r') as f:
    reader   = csv.reader(f, delimiter = ',')
    data     = list(reader)
    rowCount = len(data)

while x < rowCount:

    try:
        # Set variables and make sure they are the right format
        x         = float(data[x][0])
        y         = float(data[x][1])
        xMin      = float(data[x][2])
        xMax      = float(data[x][3])
        yMin      = float(data[x][4])
        yMax      = float(data[x][5])
        deltaTime = float(data[x][6])

        # Check for negative input, if negative throw value error
        if (x < 0) or (y < 0) or (xMin < 0) or (xMax < 0) or (yMin < 0) or ( yMax < 0) or (deltaTime < 0):
            raise ValueError

how can I check all of the values for negative numbers efficiently?

Currently, I am able to do it by using and if statement in a try/except

for example:

if (x < 0) or (y < 0) or (xMin < 0) or (etc):
    raise ValueError

This doesn't seem like the best way to do it. Is there a better way to do this?

Upvotes: 0

Views: 1057

Answers (3)

Tom Lynch
Tom Lynch

Reputation: 913

The example here is copied from Python Descriptors Demystified.

You should use descriptors to store attributes that must be constrained to certain values. The descriptor can be used to prevent invalid values from being set on any attribute defined using the descriptor class:

from weakref import WeakKeyDictionary

class NonNegativeNumber(object):
    def __init__(self):
        self.data = WeakKeyDictionary()

    def __get__(self, obj, objtype):
        return self.data.get(obj, 0)

    def __set__(self, obj, val):
        if val < 0:
            raise ValueError('must be nonnegative value')
        self.data[obj] = val

Then your original class would look like:

class EquationValues(object):
    x         = NonNegativeNumber()
    y         = NonNegativeNumber()
    xMin      = NonNegativeNumber()
    xMax      = NonNegativeNumber()
    yMin      = NonNegativeNumber()
    yMax      = NonNegativeNumber()
    deltaTime = NonNegativeNumber()

    def __init__(self, x, y, xMin, xMax, yMin, yMax, deltaTime):
        self.x = x
        self.y = y
        self.xMin = xMin
        self.xMax = xMax
        self.yMin = yMin
        self.yMax = yMax
        self.deltaTime = deltaTime

Upvotes: 1

Taku
Taku

Reputation: 33714

You can use the any statement to check if any of them is negative.

class EquationValues(object):
    def __init__(self, x, y, xMin, xMax, yMin, yMax, deltaTime):    
        self.x         = x
        self.y         = y
        self.xMin      = xMin
        self.xMax      = xMax
        self.yMin      = yMin
        self.yMax      = yMax
        self.deltaTime = deltaTime

        negatives = any(v for v in {x,y,xMin,xMax,yMin,yMax,deltaTime} if v < 0)
        if negatives:
            raise ValueError("One variable is negative")

EquationValues(0,0,0,0,0,0,-1) 
# ValueError: "One variable is negative"

You can also use locals() to get a dict of the current local scope variables.

class EquationValues(object):
    def __init__(self, x, y, xMin, xMax, yMin, yMax, deltaTime):    
        self.x         = x
        self.y         = y
        self.xMin      = xMin
        self.xMax      = xMax
        self.yMin      = yMin
        self.yMax      = yMax
        self.deltaTime = deltaTime

        if [v for v in locals().values() if isinstance(v, int) if v < 0]:
            raise ValueError("One variable is negative")

EquationValues(0,0,0,0,0,0,-1) 
# ValueError: "One variable is negative"

Upvotes: 1

alexis
alexis

Reputation: 50190

If your code actually works (it wouldn't work if these are attributes), you can rewrite it like this:

if any(var < 0 for var in (x, y, xMin, xMax, yMin, yMax, deltaTime)):
    raise ValueError

Since the variables you want to check are just a collection of names, there isn't much more you can do. If they were a list, dictionary or NamedTuple etc., there would be more room for improvement.

If the check is supposed to take place in make_equationValues() (but why didn't you just put the check in the constructor?) and you have a lot more variables than you show, you could streamline the check like this:

def make_equationValues(*args):
    if any(var < 0 for var in args):
        raise ValueError

    return EquationValues(*args)

But I wouldn't recommend this, because you no longer have an argument signature for your function, which makes it error-prone and hard to maintain.

Upvotes: 1

Related Questions