Last active
April 4, 2016 06:48
-
-
Save akaariai/08952c3dc7c24e685ea670d45b5aec91 to your computer and use it in GitHub Desktop.
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
# 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