What are the names of the magic methods for the operators "is" and "in"?
Asked Answered
F

3

17

I would like to make bool binary operations using the magic methods for these operators. For example, I can get a < b as getattr(a, '__lt__')(b) or a == b as getattr(a, '__eq__')(b).

Can I get a in b and a is b in such a way?

Fruit answered 5/12, 2016 at 18:17 Comment(0)
P
16

in is __contains__ and is does not have a dunder method. I strongly suggest you use the functions in the operator module:

a < b  => operator.lt(a, b)
a == b => operator.eq(a, b)
a in b => operator.contains(a, b)
a is b => operator.is_(a, b)
Phira answered 5/12, 2016 at 18:22 Comment(5)
Why would the operator module be preferable to the usual way?Rhatany
It wouldn't be but if you need function versions of the operators the operator module is preferable to accessing dunder methods or writing your own wrappers.Phira
I read getattr(a, '__lt__')(b) as asking for the function version of a < b which is operator.lt(a, b). You can pass around operator.lt. I saw no attempt at definition of a class in which you would define the dunder methods.Phira
I agree with you now. Your answer definitely provides a superior alternative to using getattr.Salzhauer
If you want operator.is_ with the first argument already filled in, like getattr(a, '__lt__') already has a as its first argument) you can use functools.partial. partial(operator.is_, a) is a function that only takes one argument.Morphosis
S
26

For in, the correct dunder method is __contains__.

There is no method for is, because this is equivalent to id(a) == id(b). It compares the actual object ID used under the hood by Python, so is used to compare object identity, not object contents. Overwriting it within a class would break Python's object model, so it is not allowed.

Salzhauer answered 5/12, 2016 at 18:20 Comment(0)
P
16

in is __contains__ and is does not have a dunder method. I strongly suggest you use the functions in the operator module:

a < b  => operator.lt(a, b)
a == b => operator.eq(a, b)
a in b => operator.contains(a, b)
a is b => operator.is_(a, b)
Phira answered 5/12, 2016 at 18:22 Comment(5)
Why would the operator module be preferable to the usual way?Rhatany
It wouldn't be but if you need function versions of the operators the operator module is preferable to accessing dunder methods or writing your own wrappers.Phira
I read getattr(a, '__lt__')(b) as asking for the function version of a < b which is operator.lt(a, b). You can pass around operator.lt. I saw no attempt at definition of a class in which you would define the dunder methods.Phira
I agree with you now. Your answer definitely provides a superior alternative to using getattr.Salzhauer
If you want operator.is_ with the first argument already filled in, like getattr(a, '__lt__') already has a as its first argument) you can use functools.partial. partial(operator.is_, a) is a function that only takes one argument.Morphosis
D
3

__contains__ is correct for in, with fall-back options if __contains__ isn't defined being __iter__ and __getitem__.

I am not really sure why you'd need to use getattr for is though; is is "defined" for every object in Python. There's no need to go through operator._is or (trying and failing) through getattr.

See the documentation on built-in types:

The behavior of the is and is not operators cannot be customized; also they can be applied to any two objects and never raise an exception.

(Emphasis mine)

According to the snippets you provided, which just grab a function and call it using getattr(a, "function")(b), you already have the names of the objects you need to evaluate, just use is immediately; it is always available.

Demark answered 6/12, 2016 at 9:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.