Skip to content

Instantly share code, notes, and snippets.

@akaariai
Last active April 4, 2016 06:48
Show Gist options
  • Save akaariai/08952c3dc7c24e685ea670d45b5aec91 to your computer and use it in GitHub Desktop.
Save akaariai/08952c3dc7c24e685ea670d45b5aec91 to your computer and use it in GitHub Desktop.
# 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.
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, klass, value):
self.expr_dict[klass] = value
class OperatorDict(object):
def __init__(self):
self.operator_dict = {}
def __setitem__(self, key, val):
klass, operator = key
if operator not in self.operator_dict:
self.operator_dict[operator] = MRODict()
self.operator_dict[operator][klass] = 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'
# 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])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment