I need two attributes of a class to either both be None or both be an int. There are already checks to make sure that if they are both set to something other than None, they will be ints. So at the end of the __init__ method I am calling a small function which checks if in either order, their types differ:
def both_none_or_both_something_else(a,b):
if a is None and b is not None:
return False
if b is None and a is not None:
return False
return True
>> both_none_or_both_something_else(5,None) # False
>> both_none_or_both_something_else(None,3) # False
>> both_none_or_both_something_else(5,20) # True
>> both_none_or_both_something_else(None, None) # True
Can this check of the two variables be condensed into a single line?
Simply compare the results of testing for None:
return (a is None) == (b is None)
you need Logical XOR operator: if different -> false, if equal -> true
Exclusive or (XOR, EOR or EXOR) is a logical operator which results true when either of the operands are true (one is true and the other one is false) but both are not true and both are not false. In logical condition making, the simple "or" is a bit ambiguous when both operands are true.
def both_none_or_both_something_else(a,b):
return not bool(a) != bool(b)
print (both_none_or_both_something_else(5,None))
print (both_none_or_both_something_else(None,3))
print (both_none_or_both_something_else(5,20))
print (both_none_or_both_something_else(None,None))
output:
False
False
True
True
remark:
to both be None or both be an int:
def both_none_or_both_something_else(a,b):
return not type(a) != type(b)
print (both_none_or_both_something_else(5,None))
print (both_none_or_both_something_else(None,3))
print (both_none_or_both_something_else(5,20))
print (both_none_or_both_something_else(None,None))
output:
False
False
True
True
This probably isn't what you you're looking for - but is much clearer than any one-liner.
def both_none(a,b):
return a is None and b is None
def both_not_none(a,b):
return a is not None and b is not None
def both_none_or_both_something_else(a,b):
return both_none(a,b) or both_not_none(a,b)
You could say someting like
all(x is None for x in (a, b)) or all(x is not None for x in (a,b))
but I can't really say it's an improvement. If you need this repeatedly you might achieve a certain elegance by encapsulating these into predicates:
def all_none(*args):
return all(x is None for x in args)
def none_none(*args):
return all(x is not None for x in args)
Just do:
return type(a) == type(b) and type(a) in [int, type(None)]
Related
I recently started learning python through Sololearn and got to Recursion. To get better understanding of the code, I simplified it to:
def is_even(x):
return x
def is_odd(x):
return not is_even(x)
print(is_odd(2))
The return not is_even(x) is boolean and will resulted it as False and when it passed to the def is_even(x): it still would return as False.
However, when I change the return x to print(x)
def is_even(x):
print (x)
def is_odd(x):
return not is_even(x)
print(is_odd(2))
The result would be:
2
True
How did this happen? What is going on between the return not is_even(x) and print (x).
Thank you
Maybe this will get you on track:
def returning(x):
return x
def printing(x):
print(x)
returning(2)
# 2
printing(2)
# 2
a = returning(2)
a
# 2
b = printing(2)
2
b
# None
The difference is that return returns a value from a function which can be used to pass to another function / variable. print just prints out the information but does not return any value, this is why b holds no value, but during the assigment b = printing(2) it immediately printed out what was passed to it, when a = returning(2) did not, it assigned the value to variable a.
And None is falsly in python.
None == False
# False
None == True
# False
not None == True
# True
What you are lacking is for is_even to return a bool instead of the argument passed:
def is_even(x):
return x % 2 == 0
def is_odd(x):
return not is_even(x)
is_odd(3)
# True
Your code does not have any recursion!
the function is_even() returns anything you pass to it like an integer,a character or anything else.
the function is_odd() returns a boolean;But notice the equivalent boolean value for non boolean values.
For example values like 1, 'Example', [1,2,3] and ... have True boolean value and values like 0,[], None and ... have False boolean value.
So if you pass something like "test" or 5 to is_odd(), it will return False
Is there anyone that can tell my why I get this type of return value?
>>> a = 7
>>> b = None
>>> bool(a and b)
False
>>> bool((a is None) and (b is None))
False
>>> bool((a and b) is None) # (a and b) eq False
True
>>> bool(False is None)
False
I just can't understand why this is happening.
To explain
>>> 7 and None
None
>>> bool(None)
False
So to answer:
a and b gives None and not False as you put in comment.
bool(a and b) gives False
So then when you replace a and b by its real value:
you get bool(None is None) which is True.
I believe you had bool(bool(a and b) is None) in mind, which would give False
Python's and actually returns the last value tested. For x and y, if x is false, it will return x; if x is true, it will return y. For example:
>>> 0 and ''
0
>>> 0 and 'x'
0
>>> 1 and ''
''
>>> 1 and 'x'
'x'
So when you do a and b, you get None.
Source: Documentation: Boolean Operations — and, or, not
All Python builtins and most instances have implicit truth values thanks to their __bool__ magic methods. In your case, you are working with the builtin types of int and None. In pure python, the __bool__ method for an int would like something like the following:
class int(object):
...
def __bool__(self):
return self != 0 # True as long as not equal to 0
...
And for a None it would be the following:
class NoneType(object):
...
def __bool__(self):
return False # Always False
...
Whenever an operation is done that requires the variable to be treated as a boolean (and, or, not, bool casting), these __bool__ magic methods are used to get their corresponding instance's truth value.
So with this in mind, let's look at your expressions one-by-one.
>>> bool(a and b)
False
a is the integer 7, so by its __bool__ magic method, it has a positive truth value (True). b is None, and it has a negative truth value (False). When you and variables in Python, if the first and operand has a positive truth value, and will always return the second operand (the opposite behavior can be seen with or). More information on this can be found here. So when you do a and b, None is returned because a has a positive truth value. The resulting None is then casted to a bool which as shown in None's __bool__ method above, will be False.
>>> bool((a is None) and (b is None))
False
This evaluates to False as a is not None. Here, since you are using is in the statements, you are not comparing truth value, but you are checking if they are the same object. Since 7 and None are not the same instance, it results to False, causing the rest of the statement to evaluate to False.
>>> bool((a and b) is None) # (a and b) eq False (should be None)
True
Following up from the first one, a and b will return None. since None is the same instance as None, None is None evaluates to True. The casting to bool is redundant.
>>> bool(False is None)
False
Lastly, here we are once again checking if False and None are the same instance. As they are not, this evaluates to False and the casting to bool is once again redundant.
Consider these two facts:
None is false
and returns true if both variables are true.
In every case that misleads you, you did not consider these facts.
I have trouble understanding the meaning of not in a statement such as
not int(x)
It evaluates to True if x is equal to 0.
But if x is any other number it evaluates to False.
I would like an explanation for this behavior, thanks.
not some_object will return True if some_object is falsy, i.e. if bool(some_object) will return False.
For any integer z, bool(z) will always be True unless z==0. So not int(x) is just a way of checking whether x, after you convert it to an integer (using int), is zero.
Demo:
>>> x = '-7' # this is not 0 after conversion to an integer
>>> bool(int(x))
True
>>> x = '0'
>>> bool(x) # a non-empty string is truthy
True
>>> bool(int(x))
False
>>> not int(x) # you can omit the call to bool in a boolean context
True
In a boolean context, we can omit the call to bool. Using the implicit booleanness of objects can come in handy, especially when you want to check if some object is empty (such as empty strings, sets, lists, dictionaries...).
>>> not {}
True
>>> not []
True
>>> not set()
True
>>> not ''
True
>>> not tuple()
True
>>> not 0.0
True
>>> not 0j
True
>>> not [1,2,3]
False
The methods involved here are __nonzero__ for Python2 and __bool__ for Python3. Theoretically, we could override these. Consider the following Python2 example:
>>> class LyingList(list):
... def __nonzero__(self): # for Py3, override __bool__
... return True
...
>>> liar = LyingList([])
>>> liar
[]
>>> not liar
False
uh oh!
I want to create a function that looks at three parameters and if they are all of the same type to return a boolean True value otherwise false :
This is what I have so far:
def whattype(n):
if type(n) is int:
print "True"
elif type(n) != int:
print "False"
whattype("car")
whattype(1)
whattype(2)
def whattype(a, b, c):
return type(a) == type(b) == type(c)
Explanation: First of all, your function has to take three arguments (here a, b and c). If you want to return a value, you have to use the return statement. Furthermore, it is possible to do multiple comparisons in one line, so you can check the equality of the types in one line and instantly return the result.
You can use the function like this:
>>> whattype(1, 2, "car")
False
>>> whattype(1, 2, 3)
True
Can not x and x==None give different answers if x is a class instance ?
I mean how is not x evaluated if x is a class instance ?
yes it can give different answers.
x == None
will call the __eq__() method to valuate the operator and give the result implemented compared to the None singleton.
not x
will call the __nonzero__() (__bool__() in python3) method to valuate the operator. The interpreter will convert x to a boolean (bool(x)) using the mentioned method and then inverse its returned value because of the not operator.
x is None
means that the reference x points to the None object, which is a singleton of type NoneType and will valuate false in comparaisons. The is operator tests object identity, and thus whether or not the two objects compared are the same instance of an object, and not similar objects.
class A():
def __eq__(self, other): #other receives the value None
print 'inside eq'
return True
def __nonzero__(self):
print 'inside nonzero'
return True
...
>>> x = A()
>>> x == None #calls __eq__
inside eq
True
>>> not x #calls __nonzero__
inside nonzero
False
not x is eqivalent to:
not bool(x)
Py 3.x:
>>> class A(object):
def __eq__(self, other): #other receives the value None
print ('inside eq')
return True
def __bool__(self):
print ('inside bool')
return True
...
>>> x = A()
>>> x == None #calls __eq__
inside eq
True
>>> not x #calls __bool__
inside bool
False
Yes; not uses __bool__ (in Python 3; Python 2 uses __nonzero__), and x == None can be overridden by __eq__.
(Both are shown here.)
If x is positive the not of it means negative and vice-versa.
x == None means it will only be True if x is None is True else False. Check this.
By positive I mean the if block is chosen. True is also positive.
not x is true for a wide variety of values, e.g. 0, None, "", False, [], {}, etc.
x == None is only true for the one specific value None.
If x is a class instance, then both not x and x == None will be false, but that doesn't mean that those are equivalent expressions.
Fine; that previous paragraph should read:
If x is a class instance, then both not x and x == None will be false unless someone is playing silly buggers with the class definition.