guskenny83
guskenny83

Reputation: 1373

How to force a value to be within a range?

What is the most "pythonic" way to do this?

x = some_value
bounds = [lower_bound, upper_bound]

if x < bounds[0]:
    x = bounds[0]
if x > bounds[1]:
    x = bounds[1]

Upvotes: 1

Views: 2232

Answers (5)

Stephen Ellwood
Stephen Ellwood

Reputation: 434

As an Engineer I need to do this a lot. At first I used the max/min one liner described above but its not easy to read. Many of the others, though Pythonic (which I recognise was the point of the question) and clever, are also not self documenting. In the end I wrote a function and put into a helper module for maximum reuse:

def within_limits(val, lower=None, upper=None):
""" limit a value to be within a minimum and maximum
"""
if lower and upper:
    assert upper > lower, "input range given is impossible"
if lower:
    val = max(lower, val)
if upper:
    val = min(val, upper)
return val

For me the most Pythonic practice is to delegate complexity. My shared library contains main such tiny helper functions that make my code more readable so I can concentrate on the problem I am trying to solve.

Upvotes: 0

Naman Sogani
Naman Sogani

Reputation: 959

This looks quite better to me

x = sorted([lower_bound, x, upper_bound])[1]

However if you want to consider performance, then if/elif is the best implementation.

Upvotes: 4

user1602492
user1602492

Reputation:

...and sometimes get carried away with finding a tricky way to do do something in one line.

The most important thing when programming is that you really understand the problem you want to solve. And then you want to write code, that can be read. So, pythonic does not mean it is a one-liner...

And this is not ugly or bad Python:

if x < lb:
    x = lb
elif x > ub:
    x = ub

And this is the way I would suggest to write what Naman Sogani suggested.

_, x, _ = sorted([lb, x, ub])

Upvotes: 2

kylieCatt
kylieCatt

Reputation: 11049

If you don't care what the value is as long as it's within a certain range:

>>> import random
>>> random.choice(range(lower_bound, upper_bound))

Upvotes: 0

DevShark
DevShark

Reputation: 9122

You could do:

x = max(min(some_value, upper_bound), lower_bound)

This is pythonic because it's a terse one liner, and it's more efficient than creating a list and sorting it.

Upvotes: 5

Related Questions