Override Python's 'in' operator?
MyClass.__contains__(self, item)
How do I override python's not in operator
There's no separate "notcontains" hook. in
and not in
cannot be overridden separately.
Separate __eq__
and __ne__
hooks exist because ==
and !=
might not return booleans. For example, you can't implement !=
for NumPy arrays as not (x == y)
. not in
doesn't have that issue, because both in
and not in
must return booleans.
If you look at the data model documentation, you'll see that it only documents a single __contains__
hook for both in
and not in
. You can also take a look at the implementation, where both in
and not in
call the same PySequence_Contains
C API function and then not in
applies !
to the result:
case PyCmp_IN:
res = PySequence_Contains(w, v);
if (res < 0)
return NULL;
break;
case PyCmp_NOT_IN:
res = PySequence_Contains(w, v);
if (res < 0)
return NULL;
res = !res;
break;
How do I override the `**` operator used for kwargs in variadic functions for my own user-defined classes?
Implementing .keys()
and .__getitem__()
will be sufficient to allow an instance of your custom class to be expanded using **
.
The relevant parts of the cpython source are in ceval.c which uses _PyDict_MergeEx
, and thus dict_merge
from dictobject.c which states:
/* We accept for the argument either a concrete dictionary object,
* or an abstract "mapping" object. For the former, we can do
* things quite efficiently. For the latter, we only require that
* PyMapping_Keys() and PyObject_GetItem() be supported.
*/
And indeed, implementing these two methods works as you would expect:
class MyMapping:
def __init__(self, d):
self._d = d
def __getitem__(self, k):
return self._d[k]
def keys(self):
return self._d.keys()
def foo(a, b):
print(f"a: {a}")
print(f"b: {b}")
mm = MyMapping({"a":"A", "b":"B"})
foo(**mm)
Output:
a: A
b: B
Side note: your .keys()
implementation need only return an iterable (e.g. a list would be fine), not necessarily a dict_keys
object like I do above for simplicity. That line could also have been return list(self._d.keys())
without issue.
Something unusual like the following would also work:
class MyMapping:
def __getitem__(self, k):
return 2
def keys(self):
return ["a", "b", "c"]
def foo(a, b, **kwargs):
print(f"a: {a}")
print(f"b: {b}")
print(f"kwargs: {kwargs}")
mm = MyMapping()
foo(**mm)
Output:
a: 2
b: 2
kwargs: {'c': 2}
How to override the [] operator in Python?
You need to use the __getitem__
method.
class MyClass:
def __getitem__(self, key):
return key * 2
myobj = MyClass()
myobj[3] #Output: 6
And if you're going to be setting values you'll need to implement the __setitem__
method too, otherwise this will happen:
>>> myobj[5] = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute '__setitem__'
Can I overload operators for builtin classes in Python?
You can't change str
's __add__
, but you can define how to add your class to strings. I don't recommend it, though.
class MyClass(object):
...
def __add__(self, other):
if isinstance(other, str):
return str(self) + other
...
def __radd__(self, other):
if isinstance(other, str):
return other + str(self)
...
In "asdf" + thing
, if "asdf".__add__
doesn't know how to handle the addition, Python tries thing.__radd__("asdf")
.
Any way to override the and operator in Python?
You cannot override the and
, or
, and not
boolean operators.
In Python, how to override the arithmetic operator / to produce: 1 / 0 = math.inf?
You need to define your own class and within that define methods __truediv__
(/
) and __floordiv__
(//
) at a minimum. If you only define those two +
for example would not work (see error below).
import math
class MyFloat:
def __init__(self, val):
self.val = val
def __truediv__(self, other):
if other.val == 0:
return math.inf
return self.val / other.val
def __floordiv__(self, other):
if other.val == 0:
return math.inf
return self.val // other.val
one = MyFloat(1)
zero = MyFloat(0)
print(one / zero)
print(one // zero)
// will throw an error (PyCharm will also pick up on this)
print(one + zero)
Expected output
Traceback (most recent call last):
File "/home/tom/Dev/Studium/test/main.py", line 24, in <module>
print(one + zero)
TypeError: unsupported operand type(s) for +: 'MyFloat' and 'MyFloat'
inf
inf
For a list of those special Python function see this website.
python: overload operator with different types
If you want to compare a CRational
object with an int then your __gt__
method should works with integers too. I.e., if other
is an integer, you clearly can't do something like other.b
. Here is a possible solution:
class CRational:
def __init__(self, a = 0, b = 1):
self.a = a
self.b = b
def __gt__(self, other):
if isinstance(other, CRational):
return self.a * other.b > other.a * self.b
elif isinstance(other, int):
# Compare self (a CRational object) with other (an int)
# TODO
else:
raise NotImplemented()
Now you can do something like this:
a = CRational()
if a > 3:
...
Be careful though! Even if you implement correctly all the methods, you still can't do 3 > a
. Order is important!! 3 > a
would call the __gt__
method of the int class. You can only do a > 3
, a < 3
, a >= 3
etc.
Related Topics
How to Update JSON File with Python
How to Create a Read-Only Class Property in Python
Multiple Linear Regression in Python
Full Examples of Using Pyserial Package
How to Check If a File Is a Valid Image File
Can Iterators Be Reset in Python
Python: the _Imagingft C Module Is Not Installed
Python: Download Files from Google Drive Using Url
How to Insert Newlines on Argparse Help Text
How to Write to a File, Using the Logging Python Module
Find Maximum Value of a Column and Return the Corresponding Row Values Using Pandas
Fastest Way to Convert a Dict's Keys & Values from 'Unicode' to 'Str'
How to Round the Minute of a Datetime Object
Listing Available Com Ports with Python
Combining Conda Environment.Yml with Pip Requirements.Txt
How to Get Python's Elementtree to Pretty Print to an Xml File
Replace All Occurrences of a String in a Pandas Dataframe (Python)
How to Calculate the Sum of All Columns of a 2D Numpy Array (Efficiently)