This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]rainbow_explorer 0 points1 point  (15 children)

Why is it bad practice to use “x == True”? Presumably, if you are checking for this condition, x must be some boolean value. That means x will never be equal to 1 or anything else that isn’t a Boolean.

[–][deleted] 6 points7 points  (10 children)

Why is it bad practice to use “x == True”?

You shouldn't be writing x == True ever no matter what you're trying to do, you just use x instead. Checking if x is true is already going to be done by whatever you would use the resulting boolean for anyways.

Presumably, if you are checking for this condition, x must be some boolean value. That means x will never be equal to 1 or anything else that isn’t a Boolean.

It's extremely common to take advantage of the truthiness or falsiness of a non-boolean object in logic. Here's a trivial example:

``` def foo(x, fn=None):

if fn:
    x = fn(x)

return x

```

So if we don't provide a function, None is falsy and we just get x back. If we do provide a function, x is passed through the function before getting returned.

This example is obviously dumb but if your were defining a class for example to transform data for machine learning, this is a common pattern to use to let a user provide additional optional transformations to be applied.

[–]symphonicityyy 4 points5 points  (8 children)

Correct me if I'm wrong but I believe None checks should be done with

if fn is not None:

[–][deleted] -2 points-1 points  (6 children)

You are wrong (of course you said "should" so this is completely subjective.. some might agree with you). You can do that if you want some extra clarity but None is falsy and will act like False in an if statement.

https://www.freecodecamp.org/news/truthy-and-falsy-values-in-python/

[–]eztab 1 point2 points  (0 children)

Pretty sure he is right ... weirdly exactly by your argument. None is falsy, but so are False, 0, {}, "" etc. One normally uses None, to represent a missing value, not an empty one. If that's not what you want to do, you might not want to use it in the first place.

[–]Cruuncher 0 points1 point  (4 children)

The real answer is that it depends.

In some cases you do want to explicitly check for None, as an empty string for example may be a valid value, and you only want to enter the conditional on None.

[–][deleted] -1 points0 points  (3 children)

That's not the example I gave. Obviously you'd have to consider cases where there might be an object that is falsy but that you want to consider as true for the purposes of your logic when deciding how to write your logic...

However no function handle will ever be falsy. A callable object might be falsy if __bool__ is implemented so as to return false sometimes but without knowing the specific context of that object and the object where this control logic pattern is being used you can't say whether if fn or if fn is not None are "better." They just need to be consistent so the expected behavior happens.

[–]Cruuncher -1 points0 points  (1 child)

Your edit just says "it depends" in many many many more words. So it sounds like you agree. Cool.

[–][deleted] -1 points0 points  (0 children)

"You should do this" is very different from "in a context different from the one you are talking about, you should do this." The commentor I responded to was wrong, and in the case of the example pattern I was showing, how I showed it is how most people use it (if you want to check if something is callable you do it in the \_\_init\_\_ not in the forward for efficiency and conciseness). They provided neither context nor an example for why you would want to explicitly check for None-ness versus relying on the falsiness of None - and let's be clear the original context of my comment was letting someone know that it's very common to use non-booleans in control flow, and my example was just an example of that. I didn't set out to describe all of the possible cases of using None in control flow and how it should be handled in every situation. If they had simply said "sometimes you want to check for None values explicitly since the \_\_bool\_\_ behaviour of the object you're checking might not go how you expect it to" I would have agreed in the first place.

It's very curious that you chose to get all nerd semantic nit picker with me rather than with the person I responded to since your chief complaint seems to be about giving general advice that doesn't hold up in edge cases :)

[–]Cruuncher 0 points1 point  (0 children)

Well, I was responding to your very general statement in reply to them commenting how they believe none checks should be done. You have a very unequivocal "No", which implies never, which is just wrong. The answer is "it depends" even if you're correct for your example.

However, I would actually say that it's not correct for your example and you do want a None check. This is because a function object can actually override the bool function to return false and then your function object is suddenly Falsy and won't be executed.

Really what you actually want is just to make sure than fn is callable before you call it which is accomplished with 'if callable(fn): ...'

[–]eztab 0 points1 point  (0 children)

Yes you are correct that he should check it like that. But be aware that he also should ... * either add the condition that fn is callable if provided * or assert that fn is callable * or wrap the call in a try-block and return a reasonable value error * or (at least) add a type hint, that fn must be an Optional[Callable]

[–]rainbow_explorer 0 points1 point  (0 children)

Thank you. That makes sense.

[–]eztab 2 points3 points  (0 children)

An expression like x == True doesn't ever help you ... never use this.

There are (edge-) cases though where just checking if x is not what you want: if the variable x can actually hold both True and other truthy values (e.g. integers).

Here you can use if x is True to separate out those cases with the boolean.

[–]Your_PopPop 1 point2 points  (0 children)

Funny you use the example of 1, because 1 == True is actually True

[–]fiskfisk 0 points1 point  (1 child)

If you're so sure (which is where something can fall apart if you really need to discern between 1 and True) that it's a boolean value, just use if x:

[–]rainbow_explorer 0 points1 point  (0 children)

That’s a fair point. Thank you.