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__'
Override Python's 'in' operator?
MyClass.__contains__(self, item)
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")
.
Overloading the [] operator in python class to refer to a numpy.array data member
You need to implement the __getitem__
and __setitem__
magic functions.
A complete overview for the magic methods can be found here.
import numpy as np
class MyArray():
def __init__(self):
self.data = np.zeros(10)
def __getitem__(self, key):
return self.data[key]
def __setitem__(self, key, value):
self.data[key] = value
def __repr__(self):
return 'MyArray({})'.format(self.data)
a = MyArray()
print(a[9])
print(a[1:5])
a[:] = np.arange(10)
print(a)
Which will give you this result:
0.0
[ 0. 0. 0. 0.]
MyArray([ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.])
Inheritance
If you just want to modify or add behaviour of np.ndarray, you could inherit from it. This is a little more complicated than for normal python classes, but implementing your case should be not that hard:
import numpy as np
class MyArray(np.ndarray):
def __new__(cls, shape, fill_value=0, dtype=float):
data = np.full(shape, fill_value, dtype)
obj = np.asarray(data).view(cls)
obj.fill_value = fill_value
return obj
def reset(self, fill_value=None):
if fill_value is not None:
self.fill_value = fill_value
self.fill(self.fill_value)
For more info, see here.
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}
Operator overloading in Python: handling different types and order of parameters
You also need to implement __rmul__
. When the initial call to int.__mul__(7, v)
fails, Python will next try type(v).__rmul__(v, 7)
.
def __rmul__(self, lhs):
return self * lhs # Effectively, turn 7 * v into v * 7
As Rawing points out, you could simply write __rmul__ = __mul__
for this definition. __rmul__
exists to allow for non-commutative multiplication where simply deferring to __mul__
with the operands reversed isn't sufficient.
For instance, if you were writing a Matrix
class and wanted to support multiplication by a nested list, e.g.,
m = Matrix(...) # Some 2 x 2 matrix
n = [[1, 2], [3,4]]
p = n * m
Here, the list
class wouldn't know how to multiple a list by a Matrix
instance, so when list.__mul__(n, m)
fails, Python would next try Matrix.__rmul__(m, n)
. However, n * m
and m * n
are two different results in general, so Matrix.__rmul__(m, n) != Matrix.__mul__(m, n)
; __rmul__
has to do a little extra work to generate the right answer.
Error when trying to overload an operator /
In Python 3.x, you need to overload the __floordiv__
and __truediv__
operators, not the __div__
operator. The former corresponds to the //
operation (returns an integer) and the latter to /
(returns a float).
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.
Is it possible to override operators (like __add__) in a Python metaclass?
Based on this answer, this is how I did it:
class MyMetaClass(type):
def __add__(self, other):
return "some META funny result"
class MyClass(metaclass=MyMetaClass):
def __add__(self, other):
return "some funny result"
# Works fine: "some funny result"
print(MyClass() + MyClass())
# Works fine: "some META funny result"
print(MyClass + MyClass)
Comprehensive guide to Operator Overloading in Python
I like this reference to quickly see which operators may be overloaded:
http://rgruet.free.fr/PQR26/PQR2.6.html#SpecialMethods
Here is another resource, for completeness (and also for Python 3)
http://www.python-course.eu/python3_magic_methods.php
Related Topics
Splitting a Pandas Dataframe Column by Delimiter
Naturally Sorting Pandas Dataframe
Timeout for Python Requests.Get Entire Response
What Is the Point of Indexing in Pandas
How to Clamp an Integer to Some Range
Is It Safe to Replace a Self Object by Another Object of the Same Type in a Method
Why Are There No ++ and -- Operators in Python
Python Script to Copy Text to Clipboard
Appending a Dictionary to a List - I See a Pointer Like Behavior
Flask to Return Image Stored in Database
Pyinstaller and --Onefile: How to Include an Image in the Exe File
How to Use Qscrollarea to Make Scrollbars Appear
Validate Ssl Certificates with Python
Let JSON Object Accept Bytes or Let Urlopen Output Strings
How to Find Char in String and Get All the Indexes