What does "return a in b" mean? - python

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).

Related

How does "contains" work? Does it use iter and getitem?

How does __contains__ work? For example I have a class MyClass and an instance of this class called a, when I write if val in a: I'm basically invoking __contains__, from my understanding, if __contains__ is not implemented in the class then __iter__ is invoked, which iterates between the list returned by __getitem__ (which in my example is implemented in the class) and if val is equal to some element of the list then __contains__ returns True. Is it right?
EDIT: __getitem__ in my code only returns the element of the list at a given position so I don't know how would that work together with __iter__
I think the __contains__ document is clear enough,
> Called to implement membership test operators. Should return true if
> item is in self, false otherwise. For mapping objects, this should
> consider the keys of the mapping rather than the values or the
> key-item pairs.
>
> For objects that don’t define __contains__(), the membership test
> first tries iteration via __iter__(), then the old sequence iteration
> protocol via __getitem__(), see this section in the language
> reference.
That's exactly right. More specifics here:
For user-defined classes which define the contains() method, x in
y returns True if y.contains(x) returns a true value, and False
otherwise.
For user-defined classes which do not define contains() but do
define iter(), x in y is True if some value z, for which the
expression x is z or x == z is true, is produced while iterating over
y. If an exception is raised during the iteration, it is as if in
raised that exception.
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 is y[i] or x == y[i], and no lower integer
index raises the IndexError exception. (If any other exception is
raised, it is as if in raised that exception).

Check if object is in an iterable using "is" identity instead of "==" equality

if object in lst:
#do something
As far as I can tell, when you execute this statement it is internally checking == between object and every element in lst, which will refer to the __eq__ methods of these two objects. This can have the implication of two distinct objects being "equal", which is usually desired if all of their attributes are the same.
However, is there a way to Pythonically achieve a predicate such as in where the underlying equality check is is - i.e. we're actually checking if the two references are to the same object?
3list membership in python is dictated by the __contains__ dunder method. You can choose to overwrite this for a custom implementation if you want to use the normal "in" syntax:
class my_list(list):
def __contains__(self, x):
for y in self:
if x is y:
return True
return False
4 in my_list([4, [3,2,1]])
>> True
[3,2,1] in my_list([4, [3,2,1]]) # Because while the lists are "==" equal, they have different pointers.
>>> False
Otherwise, I'd suggest kaya3's answer of using a generator check.
Use the any function:
if any(x is object for x in lst):
# ...
if you want to specifically use is then just use filter like:
filtered_list = filter(lambda n: n is object, list)

What operation is called on A in "while A:"?

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.

Does comparing using `==` compare identities before comparing values?

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.

Difference between the in keyword and __contains__ in Python

I was wondering if some one could explain the difference between the "in" keyword of Python and the contains method
I was working with a sample list and found this behavior. When are the two supposed to be used? Is there some efficiency that can be achieved if I use one over the other.
>>> my_list = ["a", "b", "c"]
>>> my_list.__contains__("a")
True
>>> "a" in my_list
True
The __contains__() method of an an object is called when you use the in statement.
For lists this is pre-defined, but you can also define your own class, add a __contains__ method and use in on the instances of that class.
You should be using in and not call __contains__() directly.
From the docs:
For the list and tuple types, x in y is true if and only if there
exists an index i such that x == y[i] is true.
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.
For user-defined classes which define the __contains__() method, x in
y is true if and only if y.__contains__(x) is true.
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.
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.
Like most magic methods, the __contains__ method is not meant to be called directly. The reason __contains__ exists is precisely so that you can write obj in container instead of having to use method-call syntax. So you should use obj in container.
Doing "a" in my_list actually calls __contains__ method of my_list if defined.
If __contains__ is not defined then __getitem__ is used.

Categories