I’m trying to make a class that can keep track of basic join operations between instances of that class. See the minimum reproducible example below
from __future__ import annotations
from typing import Literal
class Block():
jointype_lookup = {'both': '>', 'right': '>>', 'left': '<<'}
def __init__(self, name):
self.name = name
self.join_stack = [self]
self.join_stack_types = []
@classmethod
def _from_join_opertation(cls, block1: Block, block2: Block, join_type: Literal['left', 'right', 'both']):
self = cls.__new__(cls)
self.join_stack = block1.join_stack + block2.join_stack
self.join_stack_types = block1.join_stack_types + [join_type] + block2.join_stack_types
return self
def __gt__(self, other: Block):
# join both
return_graph_obj = Block._from_join_opertation(self, other, 'both')
return return_graph_obj
def __rshift__(self, other: Block):
# join right
return_graph_obj = Block._from_join_opertation(self, other, 'right')
return return_graph_obj
def __lshift__(self, other: Block):
# join left
return_graph_obj = Block._from_join_opertation(self, other, 'left')
return return_graph_obj
def __str__(self):
command = f"{self.join_stack[0].name}"
for i, type in enumerate(self.join_stack_types):
command += f" {self.jointype_lookup[type]} {self.join_stack[i+1].name}"
return command
command = Block('oxygen') >> Block('hydrogen') >> Block('helium') >> Block('carbon')
print(command)
# output: oxygen >> hydrogen >> helium >> carbon
command = Block('oxygen') << Block('hydrogen') << Block('helium') << Block('carbon')
print(command)
# output: oxygen << hydrogen << helium << carbon
command = Block('oxygen') > Block('hydrogen') > Block('helium') > Block('carbon')
print(command)
# output: helium > carbon
The last example is the problem. I can fix this by surrounding each successive operation in brackets (which is not ideal for my use case), but I’m keen on understanding why the comparison operators seem to work fundamentally differently to the other operators and if there is a way to change their behaviour
1