1 # Stores properties associated with the class of an object.
4 # Would it be nice to have support for more than one resolver per
5 # class? In the meanwhile, they could collude using a dispatch
8 # Do you need access to the actual resolver?
10 # Resolvers get the sequence because they may do a per-object lookup.
12 # Could cache search results for better performance.
15 # Dictionary which creates dictionary elements, so lookups never fail.
16 # The new elements are always dictionaries.
17 class CreateDict(dict):
18 def __getitem__(self, key):
19 return self.setdefault(key,{})
21 class PropertyManager:
23 self.class_property = CreateDict()
24 self.class_property_resolver = CreateDict()
25 self.class_resolver = {}
27 def resolve(self, obj, property):
30 except AttributeError:
31 raise KeyError("built-in instance")
33 return self.resolve_class(klass, property)
35 def resolve_class(self, klass, property):
36 # Hopefully, we'll find the hit right away
38 return self.class_property[klass][property]
42 # Is there a property resolver?
44 return self.class_property_resolver[klass][property](
45 self, klass, property)
49 # What about the class resolver?
51 return self.class_resolver[klass](self, klass, property)
55 # That failed, so we walk up the class tree, depth-first and
56 # left-to-right (same as Python). For each class, check if
57 # the property exists, then check if the property resolver
58 # exists, and finally, check for the class resolver.
60 bases = list(klass.__bases__)
64 return self.class_property[base][property]
68 return self.class_property_resolver[base][property](
69 self, klass, property)
73 return self.class_resolver[base](self, klass, property)
77 # this is why the search is depth-first/right-left
78 bases[:0] = list(base.__bases__)
79 raise KeyError("cannot find property %s for class %s" \
83 default_manager = PropertyManager()