if (foo or bar or baz) is None: - python

I've been refactoring some rather crufty code and came across the following rather odd construct:
#!/usr/bin/env python2.7
# ...
if (opts.foo or opts.bar or opts.baz) is None:
# (actual option names changed to protect the guilty)
sys.stderr.write("Some error messages that these are required arguments")
... and I was wondering if this would ever make any conceivable sense.
I changed it to something like:
#!/usr/bin/env python2.7
if None in (opts.foo, opts.bar, opts.baz):
# ...
I did fire up an interpreter and actually try the first construct ... it only seems to work if the values are all false and the last of these false values is None. (In other words CPython's implementation seems to return the first true or last false value from a chain of or expressions).
I still suspect that the proper code should use either the any() or all() built-ins which were added 2.5 (the code in question already requires 2.7). I'm not yet sure which are the preferred/intended semantics as I'm just starting on this project.
So is there any case where this original code would make sense?

The short-circuiting behavior causes foo or bar or baz to return the first of the three values that is boolean-true, or the last value if all are boolean-false. So it basically means "if all are false and the last one is None".
Your changed version is slightly different. if None in (opts.foo, opts.bar, opts.baz) will, for instance, enter the if block if opts.foo is None and the other two are 1, whereas the original version will not (because None or 1 or 1 will evaluate to 1, which is not None). Your version will enter the if when any of the three is None, regardless of what the other two are, whereas the original version will enter the if only if the last is None and the other two are any boolean-false values.
Which of the two versions you want depends on how the rest of the code is structured and what values the options might take (in particular, whether they might have boolean-false values other than None, such as False or 0 or an empty string). Intuitively your version does seem more reasonable, but if the code has peculiar tricks like this in it, you never know what corner cases might emerge.

It's behaving that way because or is an short-circuit operator, details are in docs. Thus your first if statement is equal to:
if opts.baz is None
We could guess what author of that code expected. I think that, as you mentioned, he thought of using not all([opts.foo, opts.bar, opts.baz]).

I would prefer
if any(i is None for i in (opts.foo, opts.bar, opts.baz))
as it exactly expresses the intended goal.
OTOH,
not all([opts.foo, opts.bar, opts.baz])
does check for falseness, not for None.
The original code doesn't seem to make sense; it seems to have been written by someone unaware what they are doing.

let's try both two of your code:
In [20]: foo = True
In [22]: bar = None
In [23]: baz = None
In [24]: foo or bar or baz
Out[24]: True
In [25]: (foo or bar or baz) is None
Out[25]: False
In [28]: ((foo or bar or baz) is None) == (None in (foo, bar, baz))
Out[28]: False
You can see your rewrite is not same as the original code.
Your first condition only return True when all of your variables is None
In [19]: (None or None or None) is None
Out[19]: True
so you can rewrite your first condition to:
if foo == bar == bar == None:

Related

What is the difference between None and boolean (True, False) in python's default argument values?

In function definitions, one can define a boolean default argument's values as argument=None or argument=False.
An example from pandas concat:
def concat(
objs,
axis=0,
join="outer",
join_axes=None,
ignore_index=False,
keys=None,
levels=None,
names=None,
verify_integrity=False,
sort=None,
copy=True,
):
While both usages can be found, why would one be using one over the other?
Is there any PEP on this?
True and False are specific bool values. Use default False when you have a bool field and you want the default to be False.Don't use False as a value for a non-bool field.
None is used as a generic placeholder when the value will be set later. It can be typed as Optional[T], which is equivalent to Union[T, None].
You might be thinking of None and False as similar because they're both "falsy" (bool(x) returns False), but the same is true of several other values, [] () {} 0 0.0, etc and we don't use them like None either.
In your example, True/False are used where the field takes a boolean value. None is used where the field takes an Optional[List]. (The exception is sort: Optional[bool], which is being used temporarily as an ad-hoc compatibility tool for a deprecated behavior.)
True and False are boolean values, so in this context None can make sense if you have a boolean variable that can be in an 'unknown' state. Strictly spoken, such a variable would not be boolean, but in reality, this can be quite handy.
For example:
# In the beginning, we simply don't know if it's true or not
is_cat_alive = None
# But later we will determine the status
is_cat_alive = check_cat_in(box)
Note that if you are using a boolean like this, then if is_cat_alive will be false when is_cat_alive is either False or None which makes sense but might not be what you want to know. So to explicitly check for a dead cat, you would have to use if is_cat_alive == False.
None is similar to a null value if you know anything about those. Someone might say it's equal to 0, but None means that it is nothing. Say age = None for example. age is a variable, but it is equal to nothing. False is an actual value. True and False can be used as an indicator such as
def name_check(name)
if name == "Brittany":
return True
else:
return False
Calling that function with "Brittany" as the name parameter would return True which could be used in other conditions as well. Hope this helped! Good luck!
Look at the following code:
my_string = ''
my_other_string = None
my_final_string = 'I am a string'
If you were using these within python in something like an if statement they would actually equal the following:
my_string = False
my_other_string = None
my_final_string = True
Hope that helps

Is using min/max on boolean lists in Python bad?

So I have a condition I want to happen only when all items in a list evaluate to true. An example of this might be something like a list of functions which return a boolean (not actually my situation but easier to explain):
def foo():
# do something
def bar():
# do something
def baz():
# do something
fncs = [foo, bar, baz]
if <every element in [fnc() for fnc in fncs] evaluates to true>:
# do something
I know I can definitely do this:
all_true = True
for fnc in fncs:
if not fnc():
all_true = False
if all_true:
# do something
But, I was wondering if this is poor form:
if min([fnc() for fnc in fncs]):
# do something
Alternatively, I could try to select all false elements during list comprehension and check whether the list is occupied (this works because bool(arr) where arr is a list returns False if and only if arr is empty):
if not [None for fnc in fncs if not fnc()]:
# do something
I feel like the "min" is a lot cleaner than the last method, and while the first one is easiest to understand for novices it should be pretty clear what's going on. I could alternately make it clearer through aliasing:
all_true = min
if all_true([fnc() for fnc in fncs]):
# do something
I'm sure I missed other ways to do this as well. I'm wondering what method would be most desirable.
Thanks for the help!
Using min is not "bad", but it is unclear what you are trying to do and will do unnecessary work. You should use all instead.
if all(fnc() for fnc in fncs):
# do something
This will return True if all values are True, and False otherwise. It has the added benefit of quitting early if any value is False, unlike min which must run through the entire sequence at least once.
If you find that you need to evaluate if the are all False, I recommend any (well, not any(...), specifically) which has a similar "quit as soon as possible" behavior.
You're probably looking for all built-in function:
print all(f() for f in [foo, bar, baz])

Can I "hook" variable reassignment?

Python is a language in which the following is possible:
>>> class A(object):
... def __eq__(self, _):
... return True
...
>>> a = A()
>>> a == "slfjghsjdfhgklsfghksjd"
True
>>> a == -87346957234576293847658734659834628572384657346573465
True
>>> a == None
True
>>> a is None
False
Other things, like gt and lt are also "overloadable"1 in this way, and this is a great feature, in my opinion.
I'm curious if the = assignment operator is also "overloadable"1 in a similar kind of fashion, or if I'd have to recompile Python into NotPython to do this.
(As far as I know, classes and objects don't implement some __assign__ method; that's implemented with the C bytecode runner/compiler.)
Specifically, I want to implement an LL(k) parser by iterating on a token list, without using an iterator such that I can change the iterator's index arbitrarily to jump to a given token.
The catch is that on a given cycle of the loop, if I've already arbitrarily modified the index in preparation for the next cycle (something I'll surely do a lot) the last thing I want to do is mess up that variable by adding one to it as if it hadn't been changed.
Probably the easiest, simplest solution to this is to have a flag that gets set on jumps and which is reset to False every cycle, but this can and will introduce tiny hiding bugs I'd like to avoid ahead of time. (See here for what I mean -- this is the pathetic iterative LL(1) parser I'm rewriting, and I want its reincarnation to be somewhat maintainable and/or readable.)
The flag solution:
idx = 0
while True:
jmpd = False
# maybe we jumped, maybe we didn't; how am I to know!?!?
if jmpd == False:
idx += 1
Great! One big drawback: at each possible branch resulting in an arbitrary change in the index, I have to set that flag. Trivial, perhaps (obviously in this example), but to me it seems like a harbinger of unreadable, bug-friendly code.
What's the best way, without using a second variable, to test if a value's changed over time?
If your answer is, "there isn't one, just be quiet and use a flag variable", then I congratulate you for promoting bad code design. /s
1Yeah, I know it's not technically operator overloading; have you a better, more quickly understandable term?
You can use another magic method to intercept assignment of the attribute. It's called __setattr__(). Here is an example of how to use it:
In [2]: class Test(object):
def __setattr__(self, name, value):
print(name, "changed to", value)
super().__setattr__(name, value)
...:
In [3]: t = Test()
In [4]: t.name = 4
name changed to 4
In [5]: t.name = 5
name changed to 5

Check for initialized variable in Python

I'm new to Python and I'm playing a bit with some code snippets.
In my code I need to check for variable initialization and I was using this idiom:
if my_variable:
# execute some code
but reading some posts I found this other idiom is used:
if my_variable is not None:
# execute some code
Are they equivalent or is there some semantic difference?
Quoting Python documentation on boolean operations,
In the context of Boolean operations, and also when expressions are used by control flow statements, the following values are interpreted as false: False, None, numeric zero of all types, and empty strings and containers (including strings, tuples, lists, dictionaries, sets and frozensets). All other values are interpreted as true.
So, if my_variable will fail, if my_variable has any of the above mentioned falsy values where as the second one will fail only if my_variable is None. Normally the variables are initialized with None as a placeholder value and if it is not None at some point of time in the program then they will know that some other value has been assigned to it.
For example,
def print_name(name=None):
if name is not None:
print(name)
else:
print("Default name")
Here, the function print_name expects one argument. If the user provides it, then it may not be None, so we are printing the actual name passed by the user and if we don't pass anything, by default None will be assigned. Now, we check if name is not None to make sure that we are printing the actual name instead of the Default name.
Note: If you really want to know if your variable is defined or not, you might want to try this
try:
undefined_variable
except NameError as e:
# Do whatever you want if the variable is not defined yet in the program.
print(e)
No if 0 would be False where if my_variable was actually 0 then if my_variable is not None: would be True, it would be the same for any Falsey values.
In [10]: bool([])
Out[10]: False
In [11]: bool(0)
Out[11]: False
In [12]: bool({})
Out[12]: False
In [13]: [] is not None
Out[13]: True
In [14]: 0 is not None
Out[14]: True
It's worth noting that python variables cannot be uninitialised. Variables in python are created by assignment.
If you want to check for actual uninitialisation, you should check for (non) existence, by catching the NameError exception.
Taking an example of a null string i.e. '' which is not None
>>> a = ""
>>> if a:
... print (True)
...
>>> if a is not None:
... print (True)
...
True
>>>
And a boolean value
>>> a = False
>>> if a:
... print (True)
...
>>> if a is not None:
... print (True)
...
True
>>>
Thus they are not equivalent
Check if variable exists is in globals dict, if not initialize variable.
if 'ots' not in globals():
ots=0.0

Boolean identity == True vs is True

It is standard convention to use if foo is None rather than if foo == None to test if a value is specifically None.
If you want to determine whether a value is exactly True (not just a true-like value), is there any reason to use if foo == True rather than if foo is True? Does this vary between implementations such as CPython (2.x and 3.x), Jython, PyPy, etc.?
Example: say True is used as a singleton value that you want to differentiate from the value 'bar', or any other true-like value:
if foo is True: # vs foo == True
...
elif foo == 'bar':
...
Is there a case where using if foo is True would yield different results from if foo == True?
NOTE: I am aware of Python booleans - if x:, vs if x == True, vs if x is True. However, it only addresses whether if foo, if foo == True, or if foo is True should generally be used to determine whether foo has a true-like value.
UPDATE: According to PEP 285 § Specification:
The values False and True will be singletons, like None.
If you want to determine whether a value is exactly True (not just a true-like value), is there any reason to use if foo == True rather than if foo is True?
If you want to make sure that foo really is a boolean and of value True, use the is operator.
Otherwise, if the type of foo implements its own __eq__() that returns a true-ish value when comparing to True, you might end up with an unexpected result.
As a rule of thumb, you should always use is with the built-in constants True, False and None.
Does this vary between implementations such as CPython (2.x and 3.x), Jython, PyPy, etc.?
In theory, is will be faster than == since the latter must honor types' custom __eq__ implementations, while is can directly compare object identities (e.g., memory addresses).
I don't know the source code of the various Python implementations by heart, but I assume that most of them can optimize that by using some internal flags for the existence of magic methods, so I suspect that you won't notice the speed difference in practice.
Never use is True in combination with numpy (and derivatives such as pandas):
In[1]: import numpy as np
In[2]: a = np.array([1, 2]).any()
In[4]: a is True
Out[4]: False
In[5]: a == True
Out[5]: True
This was unexpected to me as:
In[3]: a
Out[3]: True
I guess the explanation is given by:
In[6]: type(a)
Out[6]: numpy.bool_
is there any reason to use if foo == True rather than if foo is True?"
>>> d = True
>>> d is True
True
>>> d = 1
>>> d is True
False
>>> d == True
True
>>> d = 2
>>> d == True
False
Note that bool is a subclass of int, and that True has the integer value 1. To answer your question, if you want to check that some variable "is exactly True", you have to use the identity operator is. But that's really not pythonic... May I ask what's your real use case - IOW : why do you want to make a difference between True, 1 or any 'truth' value ?
edit: regarding:
Is there a case where using if foo is True would yield different results from if foo == True?
there is a case, and it's this:
In [24]: 1 is True
Out[24]: False
In [25]: 1 == True
Out[25]: True
additionally, if you're looking to use a singleton as a sentinel value, you can just create an object:
sentinel_time = object()
def f(snth):
if snth is sentinel_time:
print 'got em!'
f(sentinel_time)
you don't want to use if var == True:, you really want if var:.
imagine you have a list. you don't care if a list is "True" or not, you just want to know whether or not it's empty. so...
l = ['snth']
if l:
print l
check out this post for what evaluates to False: Evaluation of boolean expressions in Python
Using foo is True instead of foo == True (or just foo) if is most of the time not what you want.
I have seen foo is True used for checking that the parameter foo really was a boolean.
It contradicts python's duck-typing philosophy (you should in general not check for types. A function acting differently with True than with other truthy values is counter-intuitive for a programmer who assumes duck-typing)
Even if you want to check for types, it is better to do it explicity like :
def myFunction(foo):
if not isinstance(foo, bool):
raise ValueError("foo should be a boolean")
>>> myFunction(1)
Exception: ValueError "foo should be a boolean"
For several reasons:
Bool is the only type where the is operator will be equivalent to isinstance(a, bool) and a. The reason for that is the fact that True and False are singletons. In other words, this works because of a poorly known feature of python (especially when some tutorials teach you that True and False are just aliases for 1 and 0).
If you use isinstance and the programmer was not aware that your function did not accept truthy-values, or if they are using numpy and forgot to cast their numpy-boolean to a python-boolean, they will know what they did wrong, and will be able to debug.
Compare with
def myFunction(foo):
if foo is True:
doSomething()
else:
doSomethingElse()
In this case, myFunction(1) not only does not raise an exception, but probably does the opposite of what it was expected to do. This makes for a hard to find bug in case someone was using a numpy boolean for example.
When should you use is True then ?
EDIT: this is bad practice, starting from 3.9, python raises a warning when you try to use is to compare with a literal. See # JayDadhania's comment below. In conclusion is should not be used to compare to literals, only to check the equality of memory address.
Just don't use it. If you need to check for type, use isinstance.
Old paragraph:
Basically, use it only as a shorthand for isinstance(foo, bool) and foo
The only case I see is when you explicitely want to check if a value is true, and you will also check if the value is another truthy value later on. Examples include:
if foo is True:
doSomething()
elif foo is False:
doSomethingElse()
elif foo is 1: #EDIT: raises a warning, use == 1 instead
doYetSomethingElse()
else:
doSomethingElseEntirely()
Here's a test that allows you to see the difference between the 3 forms of testing for True:
for test in ([], [1], 0, 1, 2):
print repr(test), 'T' if test else 'F', 'T' if test == True else 'F', 'T' if test is True else 'F'
[] F F F
[1] T F F
0 F F F
1 T T F
2 T F F
As you can see there are cases where all of them deliver different results.
Most of the time, you should not care about a detail like this. Either you already know that foo is a boolean (and you can thus use if foo), or you know that foo is something else (in which case there's no need to test). If you don't know the types of your variables, you may want to refactor your code.
But if you really need to be sure it is exactly True and nothing else, use is. Using == will give you 1 == True.

Categories