Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save vipranarayan14/b11f67e587c2ea92e310a54f6c70cf00 to your computer and use it in GitHub Desktop.
Save vipranarayan14/b11f67e587c2ea92e310a54f6c70cf00 to your computer and use it in GitHub Desktop.
Python Operator Overloading Experiments
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Python Operator Overloading Experiments\n",
"\n",
"This notebook explores the concept of operator overloading in Python through custom class implementations and examples."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## All Possible Operator Overloads in Python\n",
"\n",
"Python lets you overload almost every built-in operator using special (dunder) methods. Here’s a full list.\n",
"\n",
"(Source: ChatGPT)\n",
"\n",
"---\n",
"\n",
"### 1️⃣ Arithmetic Operators\n",
"\n",
"| Operator | Method | Example |\n",
"|----------|--------|---------|\n",
"| + | `__add__(self, other)` | `a + b` |\n",
"| - | `__sub__(self, other)` | `a - b` |\n",
"| * | `__mul__(self, other)` | `a * b` |\n",
"| / | `__truediv__(self, other)` | `a / b` |\n",
"| // | `__floordiv__(self, other)` | `a // b` |\n",
"| % | `__mod__(self, other)` | `a % b` |\n",
"| ** | `__pow__(self, other)` | `a ** b` |\n",
"\n",
"**🔹 Example: Overloading `+` for String Concatenation**\n",
"\n",
"```python\n",
"class Name:\n",
" def __init__(self, first, last):\n",
" self.first = first\n",
" self.last = last\n",
"\n",
" def __add__(self, other):\n",
" return Name(self.first, self.last + \"-\" + other.last)\n",
"\n",
" def __str__(self):\n",
" return f\"{self.first} {self.last}\"\n",
"\n",
"n1 = Name(\"John\", \"Doe\")\n",
"n2 = Name(\"Jane\", \"Smith\")\n",
"print(n1 + n2) # John Doe-Smith\n",
"```\n",
"\n",
"---\n",
"\n",
"### 2️⃣ Comparison Operators\n",
"\n",
"| Operator | Method | Example |\n",
"|----------|--------|---------|\n",
"| == | `__eq__(self, other)` | `a == b` |\n",
"| != | `__ne__(self, other)` | `a != b` |\n",
"| < | `__lt__(self, other)` | `a < b` |\n",
"| <= | `__le__(self, other)` | `a <= b` |\n",
"| > | `__gt__(self, other)` | `a > b` |\n",
"| >= | `__ge__(self, other)` | `a >= b` |\n",
"\n",
"**🔹 Example: Overloading `==` for Custom Comparison**\n",
"\n",
"```python\n",
"class Person:\n",
" def __init__(self, name, age):\n",
" self.name = name\n",
" self.age = age\n",
"\n",
" def __eq__(self, other):\n",
" return self.age == other.age\n",
"\n",
"p1 = Person(\"Alice\", 30)\n",
"p2 = Person(\"Bob\", 30)\n",
"print(p1 == p2) # True (compares by age)\n",
"```\n",
"\n",
"---\n",
"\n",
"### 3️⃣ Bitwise Operators\n",
"\n",
"| Operator | Method | Example |\n",
"|----------|--------|---------|\n",
"| & | `__and__(self, other)` | `a & b` |\n",
"| \\| | `__or__(self, other)` | `a \\| b` |\n",
"| ^ | `__xor__(self, other)` | `a ^ b` |\n",
"| << | `__lshift__(self, other)` | `a << b` |\n",
"| >> | `__rshift__(self, other)` | `a >> b` |\n",
"| ~ | `__invert__(self)` | `~a` |\n",
"\n",
"**🔹 Example: Overloading `&` for Custom Filtering**\n",
"\n",
"```python\n",
"class Mask:\n",
" def __init__(self, data):\n",
" self.data = data # List of Booleans\n",
"\n",
" def __and__(self, other):\n",
" return Mask([a and b for a, b in zip(self.data, other.data)])\n",
"\n",
" def __repr__(self):\n",
" return str(self.data)\n",
"\n",
"mask1 = Mask([True, False, True])\n",
"mask2 = Mask([False, True, True])\n",
"print(mask1 & mask2) # [False, False, True]\n",
"```\n",
"\n",
"---\n",
"\n",
"### 4️⃣ Assignment Operators\n",
"\n",
"These can’t be overloaded directly, but they work automatically if the base operator is overloaded:\n",
"- `+=` → Calls `__iadd__`\n",
"- `-=` → Calls `__isub__`\n",
"- `*=` → Calls `__imul__`\n",
"- `/=` → Calls `__itruediv__`\n",
"- `//=` → Calls `__ifloordiv__`\n",
"- `%=` → Calls `__imod__`\n",
"- `**=` → Calls `__ipow__`\n",
"\n",
"**🔹 Example: Overloading `+=`**\n",
"\n",
"```python\n",
"class Counter:\n",
" def __init__(self, value=0):\n",
" self.value = value\n",
"\n",
" def __iadd__(self, other):\n",
" self.value += other\n",
" return self # Must return self for in-place operations!\n",
"\n",
"counter = Counter(5)\n",
"counter += 10\n",
"print(counter.value) # 15\n",
"```\n",
"\n",
"---\n",
"\n",
"### 5️⃣ Container Operators\n",
"\n",
"| Operator | Method | Example |\n",
"|----------|--------|---------|\n",
"| `in` | `__contains__(self, item)` | `item in obj` |\n",
"| `[] (get)` | `__getitem__(self, key)` | `obj[key]` |\n",
"| `[] (set)` | `__setitem__(self, key, value)` | `obj[key] = value` |\n",
"| `del` | `__delitem__(self, key)` | `del obj[key]` |\n",
"| `len()` | `__len__(self)` | `len(obj)` |\n",
"| `iter()` | `__iter__(self)` | `for x in obj:` |\n",
"\n",
"**🔹 Example: Overloading `in` to Check Membership**\n",
"\n",
"```python\n",
"class Team:\n",
" def __init__(self, members):\n",
" self.members = members\n",
"\n",
" def __contains__(self, name):\n",
" return name in self.members\n",
"\n",
"team = Team([\"Alice\", \"Bob\", \"Charlie\"])\n",
"print(\"Alice\" in team) # True\n",
"```\n",
"\n",
"---\n",
"\n",
"### 6️⃣ Object Representation\n",
"\n",
"| Method | Purpose |\n",
"|--------|---------|\n",
"| `__str__` | Converts to a string (for `print(obj)`) |\n",
"| `__repr__` | Official string representation (`repr(obj)`) |\n",
"| `__call__` | Allows objects to be called like functions |\n",
"| `__bool__` | Defines truthiness (`if obj:`) |\n",
"\n",
"**🔹 Example: Making an Object Callable**\n",
"\n",
"```python\n",
"class Multiplier:\n",
" def __init__(self, factor):\n",
" self.factor = factor\n",
"\n",
" def __call__(self, value):\n",
" return value * self.factor\n",
"\n",
"double = Multiplier(2)\n",
"print(double(5)) # 10\n",
"```\n",
"\n",
"---\n",
"\n",
"### 7️⃣ Customizing Object Creation\n",
"\n",
"| Method | Purpose |\n",
"|--------|---------|\n",
"| `__new__` | Controls object creation (before `__init__`) |\n",
"| `__init__` | Initializes the object |\n",
"| `__del__` | Destructor (when `del obj` is called) |\n",
"\n",
"**🔹 Example: Controlling Object Creation**\n",
"\n",
"```python\n",
"class Singleton:\n",
" _instance = None\n",
" def __new__(cls):\n",
" if cls._instance is None:\n",
" cls._instance = super().__new__(cls)\n",
" return cls._instance\n",
"\n",
"a = Singleton()\n",
"b = Singleton()\n",
"print(a is b) # True (same instance)\n",
"```\n",
"\n",
"---\n",
"\n",
"### Summary\n",
"\n",
"Python allows you to overload almost everything:\n",
"- Arithmetic (`+`, `-`, `*`, etc.)\n",
"- Comparison (`==`, `>`, `<`, etc.)\n",
"- Bitwise (`&`, `|`, `~`, etc.)\n",
"- Container access (`[]`, `in`, `len()`, etc.)\n",
"- Object behavior (`__call__`, `__str__`, etc.)\n",
"- Custom object creation (`__new__`, `__init__`)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## My Experiments"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import itertools\n",
"\n",
"def long_zip(*iterables, fillvalue=\"\"):\n",
" iterators = [iter(it) for it in iterables]\n",
" \n",
" while True:\n",
" values = []\n",
" active = False\n",
" \n",
" for it in iterators:\n",
" try:\n",
" values.append(next(it))\n",
" active = True\n",
" except StopIteration:\n",
" values.append(fillvalue)\n",
" \n",
" if not active: # If all iterators are exhausted\n",
" break\n",
" \n",
" yield tuple(values)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"64\n"
]
}
],
"source": [
"import random\n",
"\n",
"def random_near_given(n, low, high, bias_strength=2):\n",
" # Generate a random number with bias towards n\n",
" return int(random.triangular(low, high, n))\n",
"\n",
"print(random_near_given(70, 50, 100)) # More likely to be near 70"
]
},
{
"cell_type": "code",
"execution_count": 88,
"metadata": {},
"outputs": [],
"source": [
"class s():\n",
" def __init__(self, string):\n",
" self._string = string\n",
"\n",
" def __str__(self):\n",
" return self._string\n",
" \n",
" def __add__(self, other):\n",
" return s(self._string + other._string)\n",
" \n",
" def __mul__(self, other):\n",
" return s(''.join(i + j for i, j in long_zip(self._string, other._string)))\n",
" \n",
" def __getitem__(self, index):\n",
" if isinstance(index, slice):\n",
" i = random_near_given(index.start, 0, len(self._string) - 1)\n",
" j = random_near_given(index.stop, 0, len(self._string) - 1)\n",
" return s(self._string[i:j])\n",
" else:\n",
" i = random_near_given(index, 0, len(self._string) - 1)\n",
" return s(self._string[i])\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"hello\n",
"world\n",
"helloworld\n",
"hheelllloowwoorrllddhello\n",
"hheelllloowwoorrllddhello\n",
"e\n"
]
}
],
"source": [
"# Create an instance of class s with the string \"hello\"\n",
"a = s(\"hello\")\n",
"\n",
"# Create another instance of class s with the string \"world\"\n",
"b = s(\"world\")\n",
"\n",
"# Print the string representation of object a\n",
"print(a)\n",
"\n",
"# Print the string representation of object b\n",
"print(b)\n",
"\n",
"# Print the result of adding objects a and b (concatenation of their strings)\n",
"print(a + b)\n",
"\n",
"# Print the result of multiplying (a + b + a) with (a + b) using the custom __mul__ method\n",
"print((a + b + a) * (a + b))\n",
"\n",
"# Print the result of multiplying (a + b) with (a + b + a) using the custom __mul__ method\n",
"print((a + b) * (a + b + a))\n",
"\n",
"# Print a random character from the string of object a using the custom __getitem__ method\n",
"print(a[1])"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.9"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment