Use of True, False, and None as return values in Python functions
The advice isn't that you should never use True
, False
, or None
. It's just that you shouldn't use if x == True
.
if x == True
is silly because ==
is just a binary operator! It has a return value of either True
or False
, depending on whether its arguments are equal or not. And if condition
will proceed if condition
is true. So when you write if x == True
Python is going to first evaluate x == True
, which will become True
if x
was True
and False
otherwise, and then proceed if the result of that is true. But if you're expecting x
to be either True
or False
, why not just use if x
directly!
Likewise, x == False
can usually be replaced by not x
.
There are some circumstances where you might want to use x == True
. This is because an if
statement condition is "evaluated in Boolean context" to see if it is "truthy" rather than testing exactly against True
. For example, non-empty strings, lists, and dictionaries are all considered truthy by an if statement, as well as non-zero numeric values, but none of those are equal to True
. So if you want to test whether an arbitrary value is exactly the value True
, not just whether it is truthy, when you would use if x == True
. But I almost never see a use for that. It's so rare that if you do ever need to write that, it's worth adding a comment so future developers (including possibly yourself) don't just assume the == True
is superfluous and remove it.
Using x is True
instead is actually worse. You should never use is
with basic built-in immutable types like Booleans (True
, False
), numbers, and strings. The reason is that for these types we care about values, not identity. ==
tests that values are the same for these types, while is
always tests identities.
Testing identities rather than values is bad because an implementation could theoretically construct new Boolean values rather than go find existing ones, leading to you having two True
values that have the same value, but they are stored in different places in memory and have different identities. In practice I'm pretty sure True
and False
are always reused by the Python interpreter so this won't happen, but that's really an implementation detail. This issue trips people up all the time with strings, because short strings and literal strings that appear directly in the program source are recycled by Python so 'foo' is 'foo'
always returns True
. But it's easy to construct the same string 2 different ways and have Python give them different identities. Observe the following:
>>> stars1 = ''.join('*' for _ in xrange(100))
>>> stars2 = '*' * 100
>>> stars1 is stars2
False
>>> stars1 == stars2
True
EDIT: So it turns out that Python's equality on Booleans is a little unexpected (at least to me):
>>> True is 1
False
>>> True == 1
True
>>> True == 2
False
>>> False is 0
False
>>> False == 0
True
>>> False == 0.0
True
The rationale for this, as explained in the notes when bools were introduced in Python 2.3.5, is that the old behaviour of using integers 1 and 0 to represent True and False was good, but we just wanted more descriptive names for numbers we intended to represent truth values.
One way to achieve that would have been to simply have True = 1
and False = 0
in the builtins; then 1 and True really would be indistinguishable (including by is
). But that would also mean a function returning True
would show 1
in the interactive interpreter, so what's been done instead is to create bool
as a subtype of int
. The only thing that's different about bool
is str
and repr
; bool
instances still have the same data as int
instances, and still compare equality the same way, so True == 1
.
So it's wrong to use x is True
when x
might have been set by some code that expects that "True is just another way to spell 1", because there are lots of ways to construct values that are equal to True
but do not have the same identity as it:
>>> a = 1L
>>> b = 1L
>>> c = 1
>>> d = 1.0
>>> a == True, b == True, c == True, d == True
(True, True, True, True)
>>> a is b, a is c, a is d, c is d
(False, False, False, False)
And it's wrong to use x == True
when x
could be an arbitrary Python value and you only want to know whether it is the Boolean value True
. The only certainty we have is that just using x
is best when you just want to test "truthiness". Thankfully that is usually all that is required, at least in the code I write!
A more sure way would be x == True and type(x) is bool
. But that's getting pretty verbose for a pretty obscure case. It also doesn't look very Pythonic by doing explicit type checking... but that really is what you're doing when you're trying to test precisely True
rather than truthy; the duck typing way would be to accept truthy values and allow any user-defined class to declare itself to be truthy.
If you're dealing with this extremely precise notion of truth where you not only don't consider non-empty collections to be true but also don't consider 1 to be true, then just using x is True
is probably okay, because presumably then you know that x
didn't come from code that considers 1 to be true. I don't think there's any pure-python way to come up with another True
that lives at a different memory address (although you could probably do it from C), so this shouldn't ever break despite being theoretically the "wrong" thing to do.
And I used to think Booleans were simple!
End Edit
In the case of None
, however, the idiom is to use if x is None
. In many circumstances you can use if not x
, because None
is a "falsey" value to an if
statement. But it's best to only do this if you're wanting to treat all falsey values (zero-valued numeric types, empty collections, and None
) the same way. If you are dealing with a value that is either some possible other value or None
to indicate "no value" (such as when a function returns None
on failure), then it's much better to use if x is None
so that you don't accidentally assume the function failed when it just happened to return an empty list, or the number 0.
My arguments for using ==
rather than is
for immutable value types would suggest that you should use if x == None
rather than if x is None
. However, in the case of None
Python does explicitly guarantee that there is exactly one None
in the entire universe, and normal idiomatic Python code uses is
.
Regarding whether to return None
or raise an exception, it depends on the context.
For something like your get_attr
example I would expect it to raise an exception, because I'm going to be calling it like do_something_with(get_attr(file))
. The normal expectation of the callers is that they'll get the attribute value, and having them get None
and assume that was the attribute value is a much worse danger than forgetting to handle the exception when you can actually continue if the attribute can't be found. Plus, returning None
to indicate failure means that None
is not a valid value for the attribute. This can be a problem in some cases.
For an imaginary function like see_if_matching_file_exists
, that we provide a pattern to and it checks several places to see if there's a match, it could return a match if it finds one or None
if it doesn't. But alternatively it could return a list of matches; then no match is just the empty list (which is also "falsey"; this is one of those situations where I'd just use if x
to see if I got anything back).
So when choosing between exceptions and None
to indicate failure, you have to decide whether None
is an expected non-failure value, and then look at the expectations of code calling the function. If the "normal" expectation is that there will be a valid value returned, and only occasionally will a caller be able to work fine whether or not a valid value is returned, then you should use exceptions to indicate failure. If it will be quite common for there to be no valid value, so callers will be expecting to handle both possibilities, then you can use None
.
Is it Pythonic to return True and None vs True and False?
This is not Pythonic, since this violates the rule "Explicit is better than implicit". As a general rule, return True
or False
for a method whose naming convention and apparent code indicate a boolean return value. None
is not a substitute for False
.
Also, consider these:
# As expected:
print(False is False)
# True
print(False == False)
# True
# If the result of the function is 'None', it has to be cast to 'bool'
# before comparing to 'False':
print(False is None)
# False
print(False == None)
# False
print(False is bool(None))
# True
print(False == bool(None))
# True
SEE ALSO:
Python Docs: Built-in Constants: https://docs.python.org/library/constants.html
Python Docs: Built-in Types: Truth Value Testing: https://docs.python.org/library/stdtypes.html#truth-value-testing
Return True, False and None in Python
It's impossible to say without seeing your actual code. Likely the reason is a code path through your function that doesn't execute a return
statement. When the code goes down that path, the function ends with no value returned, and so returns None
.
Updated: It sounds like your code looks like this:
def b(self, p, data):
current = p
if current.data == data:
return True
elif current.data == 1:
return False
else:
self.b(current.next, data)
That else clause is your None
path. You need to return the value that the recursive call returns:
else:
return self.b(current.next, data)
BTW: using recursion for iterative programs like this is not a good idea in Python. Use iteration instead. Also, you have no clear termination condition.
Why does this function return None if the number isn't even? How can I make it return False without using an else condition?
def my_function(n):
if(n % 2 == 0):
return True
return False
Since it is only one return indication, otherwise it returns none, 'nothing'. Here we have forced it to return False otherwise.
Defining a Function in python 3.6 and expecting True or False but returning None
In python every function returns None
if you do not return anything. Check your if .. .elif ... else
- where does the else
return anything?
It does not - it just calls gender()
(and then implicitly returns None
)
Change it to return the return of that function call:
if gener == '1':
print('You selected Male')
return True
elif gener == '2':
print('You selected Female')
return False
else:
print('Invalid character')
return gender()
This would fix your code, to make it better do not use recursion.
Using unneded recursion will pack new data onto call stacks all the time. You can optimize it by using a loop instead of recursing:
def gender():
"""Choose Male or Femal, return True for Male and False for Female"""
gener = "" # prepare an invalid input
while gener not in ['1','2']: # loop until input gets valid
gener = input('Choose "1" for Male or "2" for Female: ')
if gener == '1':
print('You selected Male')
return True
# elif gener == '2':
# print('You selected Female')
# return False
else: # no need for explicit check, it can only be 1 or 2
print('You selected Female')
return False
print(gender())
Sidenote for political correctness:
- not all humans on earth term themself as male or female
- not all humans on earth wan't to make this decision known
- gender might change over a livetime
How to return True and False?
Detecting duplicates is handled in many other posts: make a set from the list and check their lengths; if there's a duplicate, the set will be shorter.
Printing a Boolean value requires thinking in Boolean data, just as you've learned to think in numerical and text data.
print(sorted(lis) == list)
That's the entire case. Put them together:
print(sorted(lis) == list and len(set(lis)) == len(lis) )
python return none instead of True/False
In your program 1, only when the list is empty or the value you are searching for in the middle of the list, it would returns you boolean value, that's because you explicitly say return
if len(alist)==0
and return True
when it meets if (alist[mid]==x):
, you have to do the same for the rest conditions as well
def bin(alist,x):
if len(alist)==0:
return False
else:
mid=len(alist)//2
if (alist[mid]==x):
return True
else:
if alist[mid] < x:
#print(alist[mid+1:],x)
bin(alist[mid+1:],x) # -------> return
else:
#print(alist[:mid],x)
bin(alist[:mid],x) # -------> return
When you invoke your bin()
method recursively and expect a boolean value, you have to add return in the above highlighted lines.
Most efficient way to return True or False if a function input is within specified range? (Efficiency Problem)
The reason is that if a != num: continue
prevents anything else from happening if the numbers don't match. The loop will reach its end, and the function will return the default value of None.
The simple fix is to write the loop like this:
for num in range_list:
if == num:
return True
return False
Notice that the final return is outside the loop.
But from an efficiency point of view, testing for containment in a range by checking integer elements is a terrible idea. Use rich comparison operators instead:
def numfunc(a):
return abs(a - 100) <= 10 or abs(a - 200) <= 10
The equivalent expression not using abs
would be
def numfunc(a):
return -10 <= a - 100 <= 10 or -10 <= a - 200 <= 10
When should I use None vs False?
I would emphasize here the semantical difference rather than the behavioral.
Let's consider a couple of functions:
def find_user(criteria):
if is_met(criteria):
return User(...)
return None
# ...vs
def has_email(user):
return bool(user.email)
To me, in the above example, None
means an absence of the value, while False
means the boolean falsity.
An analogy here could be an emergence of the bool
type in C++. Historically, C (ab)used int
for boolean logic, but C++ introduced a dedicated bool
type which makes intentions behind some variables/function signatures clearer.
Related Topics
Find the Division Remainder of a Number
Matching Any Character Including Newlines in a Python Regex Subexpression, Not Globally
I'm Getting "Typeerror: 'List' Object Is Not Callable". How to Fix This Error
Why Is 'Self' in Python Objects Immutable
Max and Min Date in Pandas Groupby
How to Create Collapsible Box in Pyqt
How Do Chained Comparisons in Python Actually Work
How to Get a Single Result from a SQL Query in Python
How to Redirect Stderr in Python
How to Install Pip for Python 2.6
Typeerror: 'Range' Object Does Not Support Item Assignment
Convert Python Strings into Floats Explicitly Using the Comma or the Point as Separators
In Python, How to Test If I'm in Google App Engine Sdk
Pyinstaller Is Not Recognized as Internal or External Command
Converting Currency with $ to Numbers in Python Pandas
Are Sets Ordered Like Dicts in Python3.6