Skip to content

Instantly share code, notes, and snippets.

@akaariai
Created April 4, 2016 07:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akaariai/c7bab4d4da56c772ed48329fdc328aa0 to your computer and use it in GitHub Desktop.
Save akaariai/c7bab4d4da56c772ed48329fdc328aa0 to your computer and use it in GitHub Desktop.
import itertools
# Some test classes. We want to match the results of Python
# mro.
class Field(object):
def __eq__(self, other):
print('__eq__ of Field called')
class MyField(Field):
def __eq__(self, other):
print('__eq__ of MyField called')
class SubMyField(MyField):
def __eq__(self, other):
print('__eq__ of SubMyField called')
class OtherField(Field):
def __eq__(self, other):
print('__eq__ of OtherField called')
class ThirdField(Field):
pass # Note: no __eq__ defined at all!
class MRODict(object):
def __init__(self):
self.expr_dict = {}
def __getitem__(self, key):
lhs, rhs = key
lhs_mro = lhs.mro() if lhs else [Field]
rhs_mro = rhs.mro() if rhs else [Field]
# We try to mimick the operator matching behaviour documented at
# https://docs.python.org/2/reference/datamodel.html#coercion-rules
# (TODO: verify Python 3 has similar rules). I believe this boils down
# to:
# - check lhs_mro for the expression
# - check rhs_mro for the experssion
# - If these yield different results, use the lhs_mro match,
# *except* if the rhs klass is a subclass of the lhs class.
match = self.get_match_rule1(lhs_mro, rhs_mro)
if match:
return match
lhs_match, rhs_match = None, None
for lhs_matching in lhs_mro:
if lhs_matching in self.expr_dict:
lhs_match = self.expr_dict[lhs_matching]
break
for rhs_matching in rhs_mro:
if rhs_matching in self.expr_dict:
rhs_match = self.expr_dict[rhs_matching]
break
if lhs_match != rhs_match:
if issubclass(rhs, lhs):
return rhs_match
return lhs_match
def __setitem__(self, key, value):
self.expr_dict[key] = value
def get_match_rule1(self, lhs_mro, rhs_mro):
for item in itertools.product(lhs_mro, rhs_mro):
if item in self.expr_dict:
return self.expr_dict[item]
return None
class OperatorDict(object):
def __init__(self):
self.operator_dict = {}
def __setitem__(self, key, val):
if len(key) == 2:
klass_key, operator = key
else:
klass1, operator, klass2 = key
klass_key = klass1, klass2
if operator not in self.operator_dict:
self.operator_dict[operator] = MRODict()
self.operator_dict[operator][klass_key] = val
def __getitem__(self, key):
lhs, op, rhs = key
mro_dict = self.operator_dict[op]
return mro_dict[(lhs, rhs)]
od = OperatorDict()
# Add same operators than for the classes above
od[Field, '__eq__'] = '__eq__ of Field called'
od[MyField, '__eq__'] = '__eq__ of MyField called'
od[SubMyField, '__eq__'] = '__eq__ of SubMyField called'
od[OtherField, '__eq__'] = '__eq__ of OtherField called'
od[ThirdField, '__eq__', ThirdField] = '__eq__ of OtherField called'
# rhs is subclass of lhs -> use rhs op
Field() == MyField()
print(od[Field, '__eq__', MyField])
MyField() == Field()
print(od[MyField, '__eq__', Field])
print("****")
# rhs is subclass of lhs -> use rhs op
MyField() == SubMyField()
print(od[MyField, '__eq__', SubMyField])
SubMyField() == MyField()
print(od[SubMyField, '__eq__', MyField])
print("****")
# rhs not subclass of lhs. Use lhs op (different ops depending on order).
OtherField() == MyField()
print(od[OtherField, '__eq__', MyField])
MyField() == OtherField()
print(od[MyField, '__eq__', OtherField])
print('****')
# rhs not subclass of lhs. Use lhs op (different ops depending on order).
# (There is a strong argument to yield same results as for
# Field() == MyField() case even if that isn't what Python does).
ThirdField() == MyField()
print(od[ThirdField, '__eq__', MyField])
MyField() == ThirdField()
print(od[MyField, '__eq__', ThirdField])
print('****')
print(od[ThirdField, '__eq__', ThirdField])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment