DeprecationWarning for "if x:"? - python

The question I'm about to ask here has been asked before, but those questions/answers make no mention of what I want to know.
I recall a few months or so ago, I had a rather sizable Python script, and I was using if x: because it was shorter and I was lazy. I don't remember which version of Python, but I do remember getting a DeprecationWarning (or PendingDeprecationWarning?) about implicit comparisons to True.
Now, I'm trying to write something someone else might read. I'm using if x == True and if x is not None everywhere, and pep8 and pylint are complaining about this, saying I should use if x:.
Personally, I think if x: is far less readable, but pep8 (the program) and PEP 8 (the document) both disagree.
Google is not being very helpful in allowing me to figure in which version, if ever, Python gave a DeprecationWarning for if x:, so I wonder if perhaps the SO community can provide insight.
Should I be worrying about this at all? Does it actually matter that much?

The correct answer as to what condition to use is, in the first place, a matter of semantics rather than style. Unless x is a boolean value, 0/False or 1/True, which your question did not specify, if x: and if x == True: are semantically different conditions and often give different results. You should use whichever is the correct one for the situation. if x: is usually the correct choice, but not always. If x is specified (known) to be a boolean, then adding == True is superfluous and a waste of time for the writer, reader, and interpreter.
Under the covers, if x: means (is implemented as) if bool(x) is True in the normal meaning of this expression, and if x == True: means if bool(x == True) is True. Since x == True return a bool and bool(a_bool) is a_bool, the latter reduces to if (x == True) is True. In general, bool(x) is not the same as x == True.
if x is None: (or not None) should be used if and only if that is the proper condition. It often correct when testing the output of a function returns either an int (or string or ...) or None. In many other situations, it is usually wrong.

It is perfectly good Python, and Python 3.+ versions don't give a warning, so if you're writing code for other people to work with in the future, using if x: is perfectly fine. And by the way, on behalf of every developer who had to maintain horribly unreadable code, THANK YOU for considering the readability of your code.

I think you have several separate issues confused.
It's best to check what the style guide actually says, and double check how your code actually behaves, rather than relying only on remembered behaviour :-)
Boolean expressions are already either true or false
The expression in an if statement is always intepreted as boolean; anyone reading Python code needs to know that anyway.
So the following all mean exactly the same thing, and piling on == True does not improve readability:
if x + y:
…
if (x + y) == True:
…
if ((x + y) == True) == True:
…
if (((x + y) == True) == True) == True:
…
which is why PEP 8 says:
Don't compare boolean values to True or False using == .
Singletons should be compared using identity
The comparison of an object to None implies that value is treated specially; it is commonly used as a sentinel for special processing. It is a singleton, so comparing whether an object is merely equal to None is ambiguous.
So, if your intent is to test a value for None, you should test whether the object is none by testing its identity:
if x is None:
…
if x is not None:
…
which is why PEP 8 says:
Comparisons to singletons like None should always be done with is or is not , never the equality operators.
None is not the only value that is boolean false
There are many values which are false in a boolean context, so doing a mere if x: is not enough to tell whether an object is actually None.
Which is why PEP 8 says:
beware of writing if x when you really mean if x is not None -- e.g. when testing whether a variable or argument that defaults to None was set to some other value.

Related

Why is the last number returned when putting "and" in python? [duplicate]

First, the code:
>>> False or 'hello'
'hello'
This surprising behavior lets you check if x is not None and check the value of x in one line:
>>> x = 10 if randint(0,2) == 1 else None
>>> (x or 0) > 0
# depend on x value...
Explanation: or functions like this:
if x is false, then y, else x
No language that I know lets you do this. So, why does Python?
It sounds like you're combining two issues into one.
First, there's the issue of short-circuiting. Marcin's answer addresses this issue perfectly, so I won't try to do any better.
Second, there's or and and returning the last-evaluated value, rather than converting it to bool. There are arguments to be made both ways, and you can find many languages on either side of the divide.
Returning the last-evaluated value allows the functionCall(x) or defaultValue shortcut, avoids a possibly wasteful conversion (why convert an int 2 into a bool 1 if the only thing you're going to do with it is check whether it's non-zero?), and is generally easier to explain. So, for various combinations of these reasons, languages like C, Lisp, Javascript, Lua, Perl, Ruby, and VB all do things this way, and so does Python.
Always returning a boolean value from an operator helps to catch some errors (especially in languages where the logical operators and the bitwise operators are easy to confuse), and it allows you to design a language where boolean checks are strictly-typed checks for true instead of just checks for nonzero, it makes the type of the operator easier to write out, and it avoids having to deal with conversion for cases where the two operands are different types (see the ?: operator in C-family languages). So, for various combinations of these reasons, languages like C++, Fortran, Smalltalk, and Haskell all do things this way.
In your question (if I understand it correctly), you're using this feature to be able to write something like:
if (x or 0) < 1:
When x could easily be None. This particular use case isn't very useful, both because the more-explicit x if x else 0 (in Python 2.5 and later) is just as easy to write and probably easier to understand (at least Guido thinks so), but also because None < 1 is the same as 0 < 1 anyway (at least in Python 2.x, so you've always got at least one of the two options)… But there are similar examples where it is useful. Compare these two:
return launchMissiles() or -1
return launchMissiles() if launchMissiles() else -1
The second one will waste a lot of missiles blowing up your enemies in Antarctica twice instead of once.
If you're curious why Python does it this way:
Back in the 1.x days, there was no bool type. You've got falsy values like None, 0, [], (), "", etc., and everything else is true, so who needs explicit False and True? Returning 1 from or would have been silly, because 1 is no more true than [1, 2, 3] or "dsfsdf". By the time bool was added (gradually over two 2.x versions, IIRC), the current logic was already solidly embedded in the language, and changing would have broken a lot of code.
So, why didn't they change it in 3.0? Many Python users, including BDFL Guido, would suggest that you shouldn't use or in this case (at the very least because it's a violation of "TOOWTDI"); you should instead store the result of the expression in a variable, e.g.:
missiles = launchMissiles()
return missiles if missiles else -1
And in fact, Guido has stated that he'd like to ban launchMissiles() or -1, and that's part of the reason he eventually accepted the ternary if-else expression that he'd rejected many times before. But many others disagree, and Guido is a benevolent DFL. Also, making or work the way you'd expect everywhere else, while refusing to do what you want (but Guido doesn't want you to want) here, would actually be pretty complicated.
So, Python will probably always be on the same side as C, Perl, and Lisp here, instead of the same side as Java, Smalltalk, and Haskell.
No language that i know lets you do this. So, why Python do?
Then you don't know many languages. I can't think of one language that I do know that does not exhibit this "shortcircuiting" behaviour.
It does it because it is useful to say:
a = b or K
such that a either becomes b, if b is not None (or otherwise falsy), and if not it gets the default value K.
Actually a number of languages do. See Wikipedia about Short-Circuit Evaluation
For the reason why short-circuit evaluation exists, wikipedia writes:
If both expressions used as conditions are simple boolean variables,
it can be actually faster to evaluate both conditions used in boolean
operation at once, as it always requires a single calculation cycle,
as opposed to one or two cycles used in short-circuit evaluation
(depending on the value of the first).
This behavior is not surprising, and it's quite straightforward if you consider Python has the following features regarding or, and and not logical operators:
Short-circuit evaluation: it only evaluates operands up to where it needs to.
Non-coercing result: the result is one of the operands, not coerced to bool.
And, additionally:
The Truth Value of an object is False only for None, False, 0, "", [], {}. Everything else has a truth value of True (this is a simplification; the correct definition is in the official docs)
Combine those features, and it leads to:
or : if the first operand evaluates as True, short-circuit there and return it. Or return the 2nd operand.
and: if the first operand evaluates as False, short-circuit there and return it. Or return the 2nd operand.
It's easier to understand if you generalize to a chain of operations:
>>> a or b or c or d
>>> a and b and c and d
Here is the "rule of thumb" I've memorized to help me easily predict the result:
or : returns the first "truthy" operand it finds, or the last one.
and: returns the first "falsy" operand it finds, or the last one.
As for your question, on why python behaves like that, well... I think because it has some very neat uses, and it's quite intuitive to understand. A common use is a series of fallback choices, the first "found" (ie, non-falsy) is used. Think about this silly example:
drink = getColdBeer() or pickNiceWine() or random.anySoda or "meh, water :/"
Or this real-world scenario:
username = cmdlineargs.username or configFile['username'] or DEFAULT_USERNAME
Which is much more concise and elegant than the alternative.
As many other answers have pointed out, Python is not alone and many other languages have the same behavior, for both short-circuit (I believe most current languanges are) and non-coercion.
"No language that i know lets you do this. So, why Python do?" You seem to assume that all languages should be the same. Wouldn't you expect innovation in programming languages to produce unique features that people value?
You've just pointed out why it's useful, so why wouldn't Python do it? Perhaps you should ask why other languages don't.
You can take advantage of the special features of the Python or operator out of Boolean contexts. The rule of thumb is still that the result of your Boolean expressions is the first true operand or the last in the line.
Notice that the logical operators (or included) are evaluated before the assignment operator =, so you can assign the result of a Boolean expression to a variable in the same way you do with a common expression:
>>> a = 1
>>> b = 2
>>> var1 = a or b
>>> var1
1
>>> a = None
>>> b = 2
>>> var2 = a or b
>>> var2
2
>>> a = []
>>> b = {}
>>> var3 = a or b
>>> var3
{}
Here, the or operator works as expected, returning the first true operand or the last operand if both are evaluated to false.

"if" condition for boolean settings: == 1, == True or just omit?

Here is simple ST plugin. Is there a difference between commented lines? Personally, I don't see any difference in how they work, just a difference in visual appearance.
However, some plugin developers prefer second version (== 1), which looks just useless and ugly for me. Probably there are some reasons to prefer it?
import sublime_plugin
class ExpandUnexpandTabsCommand(sublime_plugin.EventListener):
def on_pre_save(self, view):
# if view.settings().get("translate_tabs_to_spaces"):
# if view.settings().get("translate_tabs_to_spaces") == 1:
# if view.settings().get("translate_tabs_to_spaces") == True:
view.run_command("expand_tabs")
else:
view.run_command("unexpand_tabs")
This is covered in PEP8, the official Python style guide's, "Programming Recommendations" section:
Don't compare boolean values to True or False using ==.
Yes: if greeting:
No: if greeting == True:
Worse: if greeting is True:
In other parts of the guide, they emphasize this for other use cases (e.g. testing for empty/non-empty collections should not use len()); unless a specific value is critical to your logic, use the implicit boolean nature of what you're testing (with not if it must be inverted), don't spin your wheels with comparisons that ultimately add little in terms of readability, increase fragility, and slow your code to boot.
The only reason to prefer the other approaches is if you expect there to be other truthy values that should not count as truthy. In this case, the translate_tabs_to_spaces setting is very clearly boolean in nature, so you almost certainly want to handle any truthy value the same way; if they later redesigned the setting to have a numeric value, where 0 meant "don't translate" and any positive value meant the number of spaces each tab was worth, implicit truthiness evaluation would continue to work, but for the standard four space indents, a test for == 1 or == True would suddenly decide no translation was occurring.
It depends on what the possible values are.
If the file must have 0 or 1 in it, anything else is an error, and you're reading it as an int, then you probably want == 1.
If the file can have either True or no entry at all, and you're using get(…) instead of [] so you get back None whenever it's not True, then you want to just test the truthiness. (Or maybe is not None, but definitely not == True or == 1.)
The rule is pretty simple: when writing a test, write what you mean to test.
Different tests mean different things:
if spam:: passes if spam is anything truthy. That means anything besides None, False, numeric zero, or empty containers.
if spam == 1:: passes if spam is the number 1.
if spam is True:: passes only if spam is the special constant True. If you want to make sure other truthy values fail, and only True counts, use is. You rarely want this.
if spam == True:: passes if spam is the special constant True, or some object equal to it. If you've gone out of your way to write a class whose __eq__ tests for True or something, then you might want this test, but it's hard to imagine why you would otherwise.
It happens to be true that 1 == True. But writing == True when you want to test for the number 1, or == 1 when you want to test for True but not other truthy values, is misleading to anyone who understands idiomatic Python, and mildly confusing to anyone who doesn't, and there's no benefit to anyone. So don't do it.
And writing either of those when you want to test for anything truthy isn't just misleading, it's wrong.
if view.settings().get("translate_tabs_to_spaces") is more concise and readable. There is little if ever any need to compare a Boolean to another Boolean value, and using integers of 0 and 1 to denote a Boolean value should only be considered when the programming language does not support Boolean values.

pep8 minor annoyance

In /tmp/spam.py:
n = 69
if n == True:
print 'potato'
pep8 utility complains about this conditional:
wim#SDFA100461C:/tmp$ pep8 spam.py
spam.py:3:6: E712 comparison to True should be 'if cond is True:' or 'if cond:'
the first suggestion is wrong/"worse" according to pep8 itself
the second suggestion changes the behaviour of the code
What is the best practice for a case where you actually do want to check equality with True? Is identity checking with True using is OK? Why does pep8 utility offer an alternative which is explicitly discouraged in pep8 itself?
If you really do need to check equality with True then use == and ignore PEP8, but in almost any conceivable case that isn't what you want.
If you want to know whether the value you have is one of the values Python considers to be true, use if cond:. If you want to know whether the value you have is the singleton value True then use is True, the booleans True and False are singletons so it is correct to use is in this situation.
If you need to test whether your object is the singleton True, but a linter or a code reviewer complains about is True, then isinstance(x, bool) and x is a behaviorally equivalent (but slower) substitute.
Checking x == True is a halfway house. It is true when x is True is true, and false for your case of x=69, but there are other objects which are not themselves True but for which x==True gives an unexpectedly true result such as 1 == True being true. (thanks #Ant).
So putting that together:
value of n: True 1 69 False 0
-----------------------------------------------
expression result
-----------------------------------------------
if n: True True True False False
if n is True: True False False False False
if n==True: True True False False False
Pick the row from that table which gives the results you really wanted (and the last one isn't it).
Whatever you do, I think a comment is required since the code looks funny.
If you want to check equality with True then it might be clearer to write if n == 1. Someone reading the code is less likely to misinterpret it as an attempt to test logical truth.
Of course if n has a user-defined type it's possible to define n.__eq__ such that (n == True) != (n == 1), but it would be pretty nasty. So you'd have to decide whether the subtle difference in meaning is justified by the benefit of avoiding the code looking like an incorrect logical truth test.
If the difference is not justified, and if you're absolutely required to write to the PEP8 style guide, then either use assertEqual or write expected_value = True, if n == expected_value.
If the code is a unit test for an API that for some reason defines specifically that the literal True is returned, then of course you should test if n is True, not if n == True. As before, a comment or some indirection would be needed to stop the code looking wrong.
Another option is to change the API you're testing. The reason for the style guide rules is in part to discourage people from inventing or relying on APIs that specifically define that the return value must be identical or equal to the literal True, and instead define APIs and write their code in terms of logical truth. So if you "fix" the API you can "fix" the code that tests it.
Why do you need to explicitly test for True values? You rarely, if ever do need narrow your test down to a specific type. I'd rethink your use case here; if you are building an API that'll return a bool instead of in int for out-of-band conditions, then use exceptions instead.
If you do have to test for True only, then use
if n is True:
because the boolean values are meant to be singletons like None. See the Programming recommendations section:
Comparisons to singletons like None should always be done with is or is not, never the equality operators.
Moreover, because issubtype(bool, int) is true (for historical reasons; bool was introduced rather late in Python), n == True is also true for n = 1, if you can only accept True here then you can only use is True. You could also use isinstance(n, bool) and n, which would allow for subclasses of bool, but I cannot imagine there ever be a use for such a type, and in current implementations, bool explicitly prohibits being subclassed.
The PEP 8 rule about using not using if cond is True: is specifically called out because it limits the value of cond to the bool only.
Last but not least, PEP 8 starts with this:
A Foolish Consistency is the Hobgoblin of Little Minds
[...] But most importantly: know when to be inconsistent -- sometimes the style guide just doesn't apply. When in doubt, use your best judgment. Look at other examples and decide what looks best.
Only follow PEP 8 if it suits your needs.
The second recommendation would best suit your needs. The conditional statement if cond: will return true if the condition itself is true. It will not change the behavior of the code, as it is just shorthand for if cond == True:.

What is the motivation for the "or" operator to not return a bool?

First, the code:
>>> False or 'hello'
'hello'
This surprising behavior lets you check if x is not None and check the value of x in one line:
>>> x = 10 if randint(0,2) == 1 else None
>>> (x or 0) > 0
# depend on x value...
Explanation: or functions like this:
if x is false, then y, else x
No language that I know lets you do this. So, why does Python?
It sounds like you're combining two issues into one.
First, there's the issue of short-circuiting. Marcin's answer addresses this issue perfectly, so I won't try to do any better.
Second, there's or and and returning the last-evaluated value, rather than converting it to bool. There are arguments to be made both ways, and you can find many languages on either side of the divide.
Returning the last-evaluated value allows the functionCall(x) or defaultValue shortcut, avoids a possibly wasteful conversion (why convert an int 2 into a bool 1 if the only thing you're going to do with it is check whether it's non-zero?), and is generally easier to explain. So, for various combinations of these reasons, languages like C, Lisp, Javascript, Lua, Perl, Ruby, and VB all do things this way, and so does Python.
Always returning a boolean value from an operator helps to catch some errors (especially in languages where the logical operators and the bitwise operators are easy to confuse), and it allows you to design a language where boolean checks are strictly-typed checks for true instead of just checks for nonzero, it makes the type of the operator easier to write out, and it avoids having to deal with conversion for cases where the two operands are different types (see the ?: operator in C-family languages). So, for various combinations of these reasons, languages like C++, Fortran, Smalltalk, and Haskell all do things this way.
In your question (if I understand it correctly), you're using this feature to be able to write something like:
if (x or 0) < 1:
When x could easily be None. This particular use case isn't very useful, both because the more-explicit x if x else 0 (in Python 2.5 and later) is just as easy to write and probably easier to understand (at least Guido thinks so), but also because None < 1 is the same as 0 < 1 anyway (at least in Python 2.x, so you've always got at least one of the two options)… But there are similar examples where it is useful. Compare these two:
return launchMissiles() or -1
return launchMissiles() if launchMissiles() else -1
The second one will waste a lot of missiles blowing up your enemies in Antarctica twice instead of once.
If you're curious why Python does it this way:
Back in the 1.x days, there was no bool type. You've got falsy values like None, 0, [], (), "", etc., and everything else is true, so who needs explicit False and True? Returning 1 from or would have been silly, because 1 is no more true than [1, 2, 3] or "dsfsdf". By the time bool was added (gradually over two 2.x versions, IIRC), the current logic was already solidly embedded in the language, and changing would have broken a lot of code.
So, why didn't they change it in 3.0? Many Python users, including BDFL Guido, would suggest that you shouldn't use or in this case (at the very least because it's a violation of "TOOWTDI"); you should instead store the result of the expression in a variable, e.g.:
missiles = launchMissiles()
return missiles if missiles else -1
And in fact, Guido has stated that he'd like to ban launchMissiles() or -1, and that's part of the reason he eventually accepted the ternary if-else expression that he'd rejected many times before. But many others disagree, and Guido is a benevolent DFL. Also, making or work the way you'd expect everywhere else, while refusing to do what you want (but Guido doesn't want you to want) here, would actually be pretty complicated.
So, Python will probably always be on the same side as C, Perl, and Lisp here, instead of the same side as Java, Smalltalk, and Haskell.
No language that i know lets you do this. So, why Python do?
Then you don't know many languages. I can't think of one language that I do know that does not exhibit this "shortcircuiting" behaviour.
It does it because it is useful to say:
a = b or K
such that a either becomes b, if b is not None (or otherwise falsy), and if not it gets the default value K.
Actually a number of languages do. See Wikipedia about Short-Circuit Evaluation
For the reason why short-circuit evaluation exists, wikipedia writes:
If both expressions used as conditions are simple boolean variables,
it can be actually faster to evaluate both conditions used in boolean
operation at once, as it always requires a single calculation cycle,
as opposed to one or two cycles used in short-circuit evaluation
(depending on the value of the first).
This behavior is not surprising, and it's quite straightforward if you consider Python has the following features regarding or, and and not logical operators:
Short-circuit evaluation: it only evaluates operands up to where it needs to.
Non-coercing result: the result is one of the operands, not coerced to bool.
And, additionally:
The Truth Value of an object is False only for None, False, 0, "", [], {}. Everything else has a truth value of True (this is a simplification; the correct definition is in the official docs)
Combine those features, and it leads to:
or : if the first operand evaluates as True, short-circuit there and return it. Or return the 2nd operand.
and: if the first operand evaluates as False, short-circuit there and return it. Or return the 2nd operand.
It's easier to understand if you generalize to a chain of operations:
>>> a or b or c or d
>>> a and b and c and d
Here is the "rule of thumb" I've memorized to help me easily predict the result:
or : returns the first "truthy" operand it finds, or the last one.
and: returns the first "falsy" operand it finds, or the last one.
As for your question, on why python behaves like that, well... I think because it has some very neat uses, and it's quite intuitive to understand. A common use is a series of fallback choices, the first "found" (ie, non-falsy) is used. Think about this silly example:
drink = getColdBeer() or pickNiceWine() or random.anySoda or "meh, water :/"
Or this real-world scenario:
username = cmdlineargs.username or configFile['username'] or DEFAULT_USERNAME
Which is much more concise and elegant than the alternative.
As many other answers have pointed out, Python is not alone and many other languages have the same behavior, for both short-circuit (I believe most current languanges are) and non-coercion.
"No language that i know lets you do this. So, why Python do?" You seem to assume that all languages should be the same. Wouldn't you expect innovation in programming languages to produce unique features that people value?
You've just pointed out why it's useful, so why wouldn't Python do it? Perhaps you should ask why other languages don't.
You can take advantage of the special features of the Python or operator out of Boolean contexts. The rule of thumb is still that the result of your Boolean expressions is the first true operand or the last in the line.
Notice that the logical operators (or included) are evaluated before the assignment operator =, so you can assign the result of a Boolean expression to a variable in the same way you do with a common expression:
>>> a = 1
>>> b = 2
>>> var1 = a or b
>>> var1
1
>>> a = None
>>> b = 2
>>> var2 = a or b
>>> var2
2
>>> a = []
>>> b = {}
>>> var3 = a or b
>>> var3
{}
Here, the or operator works as expected, returning the first true operand or the last operand if both are evaluated to false.

Why does python `any` return a bool instead of the value?

and and or return the last element they evaluated, but why doesn't Python's built-in function any?
I mean it's pretty easy to implement oneself like this, but I'm still left wondering why.
def any(l):
for x in l:
if x:
return x
return x
edit:
To add to the answers below, here's an actual quote from that same mailing list of ye mighty emperor on the issue:
Whether to always return True and False or the first faling / passing
element? I played with that too before blogging, and realized that the
end case (if the sequence is empty or if all elements fail the test)
can never be made to work satisfactory: picking None feels weird if
the argument is an iterable of bools, and picking False feels weird if
the argument is an iterable of non-bool objects.
Guido van Rossum (home page: http://www.python.org/~guido/)
This very issue came up up on the Python developer's mailing list in 2005, when Guido Van Rossum proposed adding any and all to Python 2.5.
Bill Janssen requested that they be implemented as
def any(S):
for x in S:
if x:
return x
return S[-1]
def all(S):
for x in S:
if not x:
return x
return S[-1]
Raymond Hettinger, who implemented any and all, responded specifically addressing why any and all don't act like and and or:
Over time, I've gotten feedback about these and other itertools recipes.
No one has objected to the True/False return values in those recipes or
in Guido's version.
Guido's version matches the normal expectation of any/all being a
predicate. Also, it avoids the kind of errors/confusion that people
currently experience with Python's unique implementation of "and" and
"or".
Returning the last element is not evil; it's just weird, unexpected, and
non-obvious. Resist the urge to get tricky with this one.
The mailing list largely concurred, leaving the implementation as you see it today.
and and or can be sensibly defined in a way that they always return one of their operands. However, any and all cannot sensibly be defined always to return a value from their input sequence: specifically they cannot do so when the list is empty. Both any and all currently have a well defined result in this situation: any returns False and all returns True. You would be forced to sometimes return a boolean value and sometimes return an item from the sequence, which makes for an unpleasant and surprising interface. Much better to be simple and consistent.
Starting Python 3.8, and the introduction of assignment expressions (PEP 572) (:= operator), we can alternatively explicitly capture a witness of an any expression or a counterexample of an all expression:
To quote a couple examples from the PEP description:
if any(len(long_line := line) >= 100 for line in lines):
print("Extremely long line:", long_line)
if all((nonblank := line).strip() == '' for line in lines):
print("All lines are blank")
else:
print("First non-blank line:", nonblank)
I asked this same question on python-ideas, and was told the reason was that any() and all() need to return a value when the sequence is empty, and those values must be False and True. This seems like a weak argument to me.
The functions can't change now, but I think they would be more useful, and better analogs of the and and or operators they generalize, if they returned the first true-ish or false-ish value they encountered.
The behavior of and and or exists for historical reasons.
Before Python had a ternary operation / conditional expression, you used and and or if you wanted to use a value on a condition. Any such expression can be rewritten with the conditional expression syntax:
true_val if condition else false_val
Essentially, they are overloaded with two functions, and for compatibility reasons, they haven't been changed.
That is not a reason to overload other operations. any seems like it should tell you whether or not a condition is true for any item, which is a boolean, so it should return a bool.
It's not immediately obvious that any's value could be either False or one of the values in the input. Also, most uses would look like
tmp = any(iterable)
if tmp:
tmp.doSomething()
else:
raise ValueError('Did not find anything')
That's Look Before You Leap and therefore unpythonic. Compare to:
next(i for i in iterable if i).doSomething()
# raises StopIteration if no value is true
The behavior of and and or was historically useful as a drop-in for the then-unavailable conditional expression.
Any returns a boolean because it effectively treats its argument as a list of bools before considering if any of them are true. It is returning the element it evaluates, but this happens to be a bool.
When would you want to use your version of any? If it's on a list of bools then you already have the correct answer. Otherwise you are just guarding against None and might be expressed as:
filter(lambda x: x != None, l)[0]
or:
[x for x in l if x != None][0]
Which is a clearer statement of intent.

Categories