Last active
March 28, 2025 10:19
-
-
Save vipranarayan14/b11f67e587c2ea92e310a54f6c70cf00 to your computer and use it in GitHub Desktop.
Python Operator Overloading Experiments
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"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