Lets say I have:
class Bar:
pass
A = Bar()
while A:
print("Foo!")
What operation is then called on A in order to determine the while loop?
I've tried __eq__ but that didn't do much.
User-defined objects are truthy, unless you define a custom __bool__:
>>> class A:
... pass
...
>>> a = A()
>>> if a: print(1)
...
1
>>> class B:
... def __bool__(self):
... return False
...
>>> b = B()
>>> if b: print(1)
...
>>>
The while statement is composed of the while keyword followed by an expression.
When an expression is used in a control flow statement the truth value of that expression is evaluated by calling the objects __bool__ method:
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. User-defined objects can customize their truth value by providing a __bool__() method.
In short, the result depends on what the __bool__ of your object returns; since you haven't specified one, a default value of True is used.
There are different methods, that can be called, to determine, whether an object evaluates to True or False.
If a __bool__-method is defined, this is called, otherwise, if __len__ is defined, its result is compared to 0.
Related
When an IF statement is called on an instance of a list object, is there a magic method that is used to evaluate whether True or False is returned? For example,
a = []
b = [1, 2, 3]
if a == b: # <---- __eq__() is called and returns False
pass
if a: # <---- what is called here that returns False?
pass
Is it:
a.__bool__ (a.__nonzero__)?
a.__len__?
or something else completely?
#ymonad gives the best answer in the question's comments, by simply referring to this doc:
https://docs.python.org/3/library/stdtypes.html#truth-value-testing
I don't want credit for this. I just can't handle it when the best answer isn't even an answer. If one can simply point to documentation, that will just about always be the best answer.
...grrrr...hey #ymonad, can I pass you a bounty or something, lol?
Experiment time!
class Falsy:
def __nonzero__(self):
print("it's __nonzero__")
return False
def __len__(self):
print("it's __len__")
return 0
def __bool__(self):
print("it's __bool__")
return False
def __eq__(self, other):
print("it's __eq__")
return False
if Falsy():
pass
# => it's __bool__
You can experiment with removing the methods to confirm which priority they are tested in (__bool__, then __len__, for Python 3).
From the documentation https://docs.python.org/2/reference/datamodel.html#object.nonzero:
object.__nonzero__(self)
Called to implement truth value testing and the built-in operation bool(); should return False or True, or their integer equivalents 0 or 1. When this method is not defined, __len__() is called, if it is defined, and the object is considered true if its result is nonzero. If a class defines neither __len__() nor __nonzero__(), all its instances are considered true.
And for Python 3 https://docs.python.org/3.7/reference/datamodel.html#object.nonzero:
object.__bool__(self)
Called to implement truth value testing and the built-in operation bool(); should return False or True. When this method is not defined, __len__() is called, if it is defined, and the object is considered true if its result is nonzero. If a class defines neither __len__() nor __bool__(), all its instances are considered true.
Try:
class MyList(list):
def __bool__(self):
return True
print(bool(list([])))
if list([]):
print('This does not print')
print(bool(MyList([])))
if MyList([]):
print('This prints')
Consulting the C-Python API documentation for PyList ...
https://docs.python.org/3.7/c-api/list.html
... we can see there is no list-specific “as bool” function. The only thing which can return the “truth” value is PyList_Size(PyObject *list), so the answer must be a.__len__() is used.
Disclaimer: At least, for CPython.
You may want to refer to this answer.
I am not sure what you mean. If I assume you are looking for a Java's .equals() equivalent, I am going to say, there is no such thing in python.
An empty list is always False in python.
I'm confused as to how the == operator works in Python 3. From the docs, eq(a, b) is equivalent to a == b. Also eq and __eq__ are equivalent.
Take the following example:
class Potato:
def __eq__(self, other):
print("In Potato's __eq__")
return True
>> p = Potato()
>> p == "hello"
In Potato's __eq__ # As expected, p.__eq__("hello") is called
True
>> "hello" == p
In Potato's __eq__ # Hmm, I expected this to be false because
True # this should call "hello".__eq__(p)
>> "hello".__eq__(p)
NotImplemented # Not implemented? How does == work for strings then?
AFAIK, the docs only talk about the == -> __eq__ mapping, but don't say anything about what happens either one of the arguments is not an object (e.g. 1 == p), or when the first object's __eq__ is NotImplemented, like we saw with "hello".__eq(p).
I'm looking for the general algorithm that is employed for equality... Most, if not all other SO answers, refer to Python 2's coercion rules, which don't apply anymore in Python 3.
You're mixing up the functions in the operator module and the methods used to implement those operators. operator.eq(a, b) is equivalent to a == b or operator.__eq__(a, b), but not to a.__eq__(b).
In terms of the __eq__ method, == and operator.eq work as follows:
def eq(a, b):
if type(a) is not type(b) and issubclass(type(b), type(a)):
# Give type(b) priority
a, b = b, a
result = a.__eq__(b)
if result is NotImplemented:
result = b.__eq__(a)
if result is NotImplemented:
result = a is b
return result
with the caveat that the real code performs method lookup for __eq__ in a way that bypasses instance dicts and custom __getattribute__/__getattr__ methods.
When you do this:
"hello" == potato
Python first calls "hello".__eq__(potato). That return NotImplemented, so Python tries it the other way: potato.__eq__("hello").
Returning NotImplemented doesn't mean there's no implementation of .__eq__ on that object. It means that the implementation didn't know how to compare to the value that was passed in. From https://docs.python.org/3/library/constants.html#NotImplemented:
Note When a binary (or in-place) method returns NotImplemented the
interpreter will try the reflected operation on the other type (or
some other fallback, depending on the operator). If all attempts
return NotImplemented, the interpreter will raise an appropriate
exception. Incorrectly returning NotImplemented will result in a
misleading error message or the NotImplemented value being returned to
Python code. See Implementing the arithmetic operations for examples.
I'm confused as to how the == operator works in Python 3. From the docs, eq(a, b) is equivalent to a == b. Also eq and __eq__ are equivalent.
No that is only the case in the operator module. The operator module is used to pass an == as a function for instance. But operator has not much to do with vanilla Python itself.
AFAIK, the docs only talk about the == -> eq mapping, but don't say anything about what happens either one of the arguments is not an object (e.g. 1 == p), or when the first object's.
In Python everything is an object: an int is an object, a "class" is an object", a None is an object, etc. We can for instance get the __eq__ of 0:
>>> (0).__eq__
<method-wrapper '__eq__' of int object at 0x55a81fd3a480>
So the equality is implemented in the "int class". As specified in the documentation on the datamodel __eq__ can return several values: True, False but any other object (for which the truthiness will be calculated). If on the other hand NotImplemented is returned, Python will fallback and call the __eq__ object on the object on the other side of the equation.
I want to create a list containing instances of a class, and initialized with numbers 0 to 9. Here's what I do:
class Element(object):
def __init__(self, elem_index=None):
if elem_index:
self._elem_index = elem_index
def get_index(self):
return self._elem_index
elements = [Element(elem_index=i) for i in range(10)]
print(elements[0].get_index())
Here's the error I get:
AttributeError: 'Element' object has no attribute '_elem_index'
You are conditionally setting _elem_index as an attribute of your instance based on the truthness of the argument elem_index you pass during initialization.
For i == 0, the first value produced by range(10), the attribute will not be set since 0 is False when evaluated in your conditional. As a result the look-up will fail when it is attempted.
Be explicit in your condition:
if elem_index is not None:
self._elem_index = elem_index
Look closer at the code in your __init__ function:
if elem_index:
self._elem_index = elem_index
What your saying translated to english is, If the boolean value of elem_index is true, give this class instance an attribute called _elem_index. Otherwise, skip this code and never define _elem_index.
With that still in mind, understand that the default first value range() generates is zero
>>> list(range(1))
[0]
>>>
And in python zero evaluates to False
>>> bool(0)
False
>>>
This means when you try to call get_index() on the first value in elements, Python raises an error because your condition in __init__ failed.
To fix this you need to more specific and tell Python exactly when you want to skip the definition of _elem_index. Instead of doing if elem_index, use this is not operator test explicitly test if elem_index is not equal toNone; if elem_index is not None. eg:
>>> var = 0
>>> if var:
print("This will not run because zero evalutes to false")
>>> if var is not None:
print("This will run because were testing if var is equal to None")
This will run because were testing if var is equal to None
>>>
I want to understand how the return statement works. I am familiar with the return statement but not aware of the return in statement. Below is an example of a class method that uses it and I would like to know what it does.
def a(self, argv):
some = self.fnc("Format Specifier")
return argv in some
value in values means "True if value is in values otherwise False"
a simple example:
In [1]: "foo" in ("foo", "bar", "baz")
Out[1]: True
In [2]: "foo" in ("bar", "baz")
Out[2]: False
So in your case return argv in some means "return True if argv is in some otherwise return False"
It means whether argv is an element of some(in Boolean value). some could be list, tuple, dict etc.
It may be more clear if you know what happens in the background. When you use x in y, that is a shortcut for y.__contains__(x)1. When you define a class, you can define your own __contains__ method that can actually return anything you want. Usually, it returns either True or False. Therefore, argv in some will be the result of argv.__contains__(some): either True or False. You then return that.
1If y does not have the __contains__ method, it is converted to an iterator and each item in it is checked for equality with x.
The return itself is of no importance here: you can interpret this as:
return (argv in some)
Now the in keyword means:
The operators in and not in test for collection membership. x in s evaluates to true if x is a member of the collection s, and false otherwise. x not in s returns the negation of x in s. The collection membership test has traditionally been bound to sequences; an object is a member of a collection if the collection is a sequence and contains an element equal to that object. However, it make sense for many other object types to support membership tests without being a sequence. In particular, dictionaries (for keys) and sets support membership testing.
Python uses a fallback mechanism where it will check whether some (in this case) supports one of the following methods:
First it checks whether some is a list or tuple:
For the list and tuple types, x in y is true if and only if there exists an index i such that either x is y[i] or x == y[i] is true.
Next it checks whether both argv and some are strings:
For the Unicode and string types, x in y is true if and only if x is a substring of y. An equivalent test is y.find(x) != -1. Note, x and y need not be the same type; consequently, u'ab' in 'abc' will return True. Empty strings are always considered to be a substring of any other string, so "" in "abc" will return True.
Now every object that implements a __contains__ method supports such in and not in test as is further described in the documentation:
For user-defined classes which define the __contains__() method, x in y is true if and only if y.__contains__(x) is true.
So besides implemented usages for dictionaries, tuples and lists, you can define your own __contains__ method for arbitrary objects.
Another way to support this functionality is the following:
For user-defined classes which do not define __contains__() but do define __iter__(), x in y is true if some value z with x == z is produced while iterating over y. If an exception is raised during the iteration, it is as if in raised that exception.
And finally:
Lastly, the old-style iteration protocol is tried: if a class defines __getitem__(), x in y is true if and only if there is a non-negative integer index i such that x == y[i], and all lower integer indices do not raise IndexError exception. (If any other exception is raised, it is as if in raised that exception).
If I compare two variables using ==, does Python compare the identities, and, if they're not the same, then compare the values?
For example, I have two strings which point to the same string object:
>>> a = 'a sequence of chars'
>>> b = a
Does this compare the values, or just the ids?:
>>> b == a
True
It would make sense to compare identity first, and I guess that is the case, but I haven't yet found anything in the documentation to support this. The closest I've got is this:
x==y calls x.__eq__(y)
which doesn't tell me whether anything is done before calling x.__eq__(y).
For user-defined class instances, is is used as a fallback - where the default __eq__ isn't overridden, a == b is evaluated as a is b. This ensures that the comparison will always have a result (except in the NotImplemented case, where comparison is explicitly forbidden).
This is (somewhat obliquely - good spot Sven Marnach) referred to in the data model documentation (emphasis mine):
User-defined classes have __eq__() and __hash__() methods by
default; with them, all objects compare unequal (except with
themselves) and x.__hash__() returns an appropriate value such
that x == y implies both that x is y and hash(x) == hash(y).
You can demonstrate it as follows:
>>> class Unequal(object):
def __eq__(self, other):
return False
>>> ue = Unequal()
>>> ue is ue
True
>>> ue == ue
False
so __eq__ must be called before id, but:
>>> class NoEqual(object):
pass
>>> ne = NoEqual()
>>> ne is ne
True
>>> ne == ne
True
so id must be invoked where __eq__ isn't defined.
You can see this in the CPython implementation, which notes:
/* If neither object implements it, provide a sensible default
for == and !=, but raise an exception for ordering. */
The "sensible default" implemented is a C-level equality comparison of the pointers v and w, which will return whether or not they point to the same object.
In addition to the answer by #jonrsharpe: if the objects being compared implement __eq__, it would be wrong for Python to check for identity first.
Look at the following example:
>>> x = float('nan')
>>> x is x
True
>>> x == x
False
NaN is a specific thing that should never compare equal to itself; however, even in this case x is x should return True, because of the semantics of is.