Overriding __or__ operator on python classes

2024/9/20 15:40:05

As a contrived example, suppose I'm generating a random fruit basket in python. I create the basket:

basket = FruitBasket()

Now I want to specify specific combinations of fruit that can occur in the basket. Suppose I'm a very picky dude, and the basket either has to be full of apples and pomegranates, oranges and grapefruit, or only bananas.

I was reading up on python operator overloading, and it seems like I could define __or__ and __and__ to get the behavior I want. I think I could do something like this:

basket.fruits = (Apple() & Pomegranate()) | (Banana()) | (Orange() & Grapefruit())

This works just fine making two classes (Or and And). When __or__ or __and__ get called, I just have return a new Or or And object:

def __or__(self, other):return Or(self, other)def __and__(self, other):return And(self, other)

What I'm trying to figure out is how do I do this without having to instantiate the fruits first? Why can't I use a static __or__ method on the base Fruit class? I've tried this but it doesn't work:

class Fruit(object):@classmethoddef __or__(self, other):return Or(self, other)

and assigning the fruit:

basket.fruits = (Apple & Pomegranate) | (Orange & Grapefruit) | (Banana)

I get an error like this:

TypeError: unsupported operand type(s) for |: 'type' and 'type'

Any thoughts on how to make this work?

Answer

__or__ is looked up on the type of the object; for a Fruit instance, that'll be Fruit; for Fruit, that is type. You can change the type of Fruit, though, by using a metaclass:

class FruitMeta(type):def __or__(self, other):return Or(self, other)class Fruit(object):__metaclass__ = FruitMeta

(For Python 3, the syntax is class Fruit(metaclass=FruitMeta): instead.)

This then does all that you want. Apple | Banana (assuming these two to be subclasses of Fruit) will produce Or(Apple, Banana).

Be very careful with this sort of design, though. It's tending into the realm of magic and may easily cause confusion.

(Complete demonstration, in Python 2.7:)

>>> class Or(object):
...     def __init__(self, a, b):
...             self.a = a
...             self.b = b
...     def __repr__(self):
...             return 'Or({!r}, {!r})'.format(self.a, self.b)
... 
>>> class FruitMeta(type):
...     def __or__(self, other):
...             return Or(self, other)
... 
>>> class Fruit(object):
...     __metaclass__ = FruitMeta
... 
>>> class Apple(Fruit): pass
... 
>>> class Banana(Fruit): pass
... 
>>> Apple | Banana
Or(<class '__main__.Apple'>, <class '__main__.Banana'>)
https://en.xdnf.cn/q/72331.html

Related Q&A

python charmap codec cant decode byte X in position Y character maps to undefined

Im experimenting with python libraries for data analysis,the problem im facing is this exceptionUnicodeDecodeError was unhandled by user code Message: charmap codeccant decode byte 0x81 in position 165…

get icloud web service endpoints to fetch data

My question may look silly but I am asking this after too much search on Google, yet not have any clue.I am using iCloud web services. For that I have converted this Python code to PHP. https://github.…

How to put result of JavaScript function into python variable. PyQt

I want to make a function in PyQt evaluateJavaScript() (or may be similar one) and than display a result of evaluated function. Real function will be much bigger, and it might not be a string.Im only …

Wrap multiple tags with BeautifulSoup

Im writing a python script that allow to convert a html doc into a reveal.js slideshow. To do this, I need to wrap multiple tags inside a <section> tag. Its easy to wrap a single tag inside anoth…

How to permanently delete a file in python 3 and higher?

I want to permanently delete a file i have created with my python code. I know the os.remove() etc but cant find anything specific to delete a file permanently.(Dont want to fill Trash with unused file…

Django. Python social auth. create profiles at the end of pipeline

I want to add a function at the end of the auth pipeline, the function is meant to check if there is a "Profiles" table for that user, if there isnt it will create a table. The Profiles mode…

What is a good audio library for validating files in Python?

Im already checking for content-type, size, and extension (Django (audio) File Validation), but I need a library to read the file and confirm that it is in fact what I hope it is (mp3 and mp4 mostly).I…

Python 3.6+: Nested multiprocessing managers cause FileNotFoundError

So Im trying to use multiprocessing Manager on a dict of dicts, this was my initial try:from multiprocessing import Process, Managerdef task(stat):test[z] += 1test[y][Y0] += 5if __name__ == __main__:te…

Convert python disassembly from dis.dis back to codeobject

Is there any way to create code object from its disassembly acquired with dis.dis?For example, I compiled some code using co = compile(print("lol"), <string>, exec) and then printed di…

Loop over a tensor and apply function to each element

I want to loop over a tensor which contains a list of Int, and apply a function to each of the elements. In the function every element will get the value from a dict of python. I have tried the easy wa…