0

I'm working on building a snake clone using Turtle. Is there a cleaner/more pythonic way to write the conditional inside of this function?

    def out_of_bounds(self, lst):
        if lst.xcor() < -260 or lst.xcor() > 260 or lst.ycor() < -260 or lst.ycor() > 260:
        return True
hixavier
  • 133
  • 7
  • It also looks like you could decorate the function with [`@staticmethod`](https://docs.python.org/3/library/functions.html#staticmethod), since it never uses self. – ljmc May 13 '22 at 17:07

8 Answers8

3

You can remove two of the comparisons by taking their absolute value

def out_of_bounds(self, lst):
    return abs(lst.xcor()) > 260 or abs(lst.ycor()) > 260
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
1

Make the boolean expression return directly, also multiline using brackets:
(to remove the need of \ at the end of lines)

Your function returns True or None, which works since None is Falsy. Better to return False if the expression fails.

def out_of_bounds(self, lst):
    return (
        lst.xcor() < -260 
        or lst.xcor() > 260 
        or lst.ycor() < -260 
        or lst.ycor() > 260
    )

ivvija
  • 482
  • 4
  • 9
1

Mostly, I'd reverse those tests and negate the result, we stay in the same condition but more readable.

In the parenthesis we test with xcor and ycor are in the ±260 interval, then we negate.

def out_of_bounds(self, lst):
    return not (-260 <= lst.xcor() <= 260 and -260 <= lst.ycor() <= 260)
ljmc
  • 4,830
  • 2
  • 7
  • 26
0

Instead of x < -a or x > a you can write not -a <= x <= a. Some may find it more readable.

TDG
  • 5,909
  • 3
  • 30
  • 51
0

you can use any, it will return true if at least one of the values is true, inside this list you can put all your conditions

def out_of_bounds(self, lst) -> bool:
    return any([
        lst.xcor() < -260, 
        lst.xcor() > 260,
        lst.ycor() < -260, 
        lst.ycor() > 260
    ])
0

It looks like the builtin abs function, which returns the absolute value, could cut down the amount of ors you need.

return abs(lst.xcor()) > 260 or abs(lst.ycor() > 260:

In general, with long chains of or or and statements, though, I like to use any or all.

# Note that you wouldn't want to collect values into a list if these are
# demanding functions, because you lose the benefit of shortcircuiting
any([True, False]) # True
all([True, False]) # False
Spenser Black
  • 317
  • 3
  • 8
  • Although you are correct about all and any, returning a boolean from within an if is bad practice. Return the test you've put in the if statement directly, negate it if necessary. – ljmc May 13 '22 at 12:18
  • I'd say that's true unless there's more behavior that should occur if the if statement evaluates to false, which I couldn't tell from the question. E.g. if x: return True; print('continuing...'). – Spenser Black May 13 '22 at 16:56
  • There is always a smell in if + return bool, because a test should just test, the rest should be handled by whatever called the test. PS: in your example, print is unreachable. – ljmc May 13 '22 at 17:09
  • I know, the example was just minimal :) Anyway, editing my response as I agree with the general idea of not using return True – Spenser Black May 13 '22 at 18:44
0

You can use the fact that upper & lower bounds are in common for x & y:

def out_of_bounds(self, lst):
    x, y = lst.xcor(), lst.ycor()
    ub_checks = map(int(-260).__gt__, (x, y)) # check if less than upper bound
    lb_checks = map(int(260).__lt__, (x, y)) #  check if greater than lower bound
    return any(ub_checks) or any(lb_checks)
cards
  • 3,936
  • 1
  • 7
  • 25
  • 1
    This is for your job safety, right ? – ljmc May 13 '22 at 13:57
  • Hi @ljmc , what do you mean? – cards May 13 '22 at 14:39
  • Your code is so so so complicated, the only reason to write it is making sure others can't understand your code and you won't get fired. Don't get me wrong, it was an interesting brain teaser, and uses very clever tricks, but it smells terribly. – ljmc May 13 '22 at 14:47
  • 1
    @ljmc Mmm I agree that could be complicated to read but at the end are just comparisons. I had smt in mind (totally different!) but I end up there... If the conditions were _irreducible_ than such approach could be interesting – cards May 13 '22 at 15:48
-1

To answer your question, this is the only solution I know about.

However, even thought there is not much information about your work I would guess lst.xcor() and lst.ycor() get/calculate the coordinates of something (your mouse pointer?).

For speed purpose I would do :

    def out_of_bounds(self, lst):
        X = lst.xcor()
        Y = lst.ycor()
        if X < -260 or X > 260 or Y < -260 or Y > 260:
            return True

Since you have to call a function it takes time, and calling it one time instead of two is (a little) faster.

and it even look a bit cleaner

Ren
  • 157
  • 12
  • 1
    Returning a boolean from within an if is bad practice. Return the test you've put in the if statement directly, negate it if necessary. – ljmc May 13 '22 at 12:17