Charles D Hixson wrote: > I want to access the values via instances of the class, so your D().a > approach isn't suitable. More like: "t = D(); t[a]"
Well, D() is an instance of D, so D().a is the same as t = D(); t.a In fact the various "a" attributes I'm accessing are class attributes of the various classes, just as you asked. If you'd rather use t[a], then things are simpler, because you won't need to override __getattribute__, with all the ugliness that comes with it: __getitem__ will suffice. > Your approach uses techniques that I'm going to need to study > carefully before I can hope to understand them. Don't worry, here's a heavily commented version, just because it's sunday and I have some free time ;-) # inheriting from object so that we can use __getattribute__ # see http://www.python.org/download/releases/2.2.3/descrintro/ class AttrSearch(object): '''Base class that customizes attribute access in all of its derived classes, choosing between all the candidates in a custom way.''' @classmethod def getclassattrset(cls, name): '''Class method (= polymorphic static method) that collects a set of the attributes with a given name from itself and from all its base classes (determined at runtime.) The only argument is the name of the attribute to look up; the return value is a list of (class_name, attribute_value) listing all the candidates found.''' # note: the first parameter 'cls' is the class of the runtime object # on which this class method is called, much like 'self' is the # object instance in instance methods # # notice: this method is defined on class AttrSearch, but if I call # it on B (subclass of AttrSearch), then 'cls' is class B! s = set() # a set is an unordered list without duplicates try: # __dict__ is the internal dictionary which holds all of a class # or of an instance's attributes # creating a tuple with the name of the runtime class 'cls' # and the value of cls's attribute named name, and adding the # tuple to the set (unless an equal tuple is already there) s.add((cls.__name__, cls.__dict__[name])) except KeyError: # ...unless the class cls has no such attribute pass # for every base class, from which the runtime class inherits: for base in cls.__bases__: try: # call this same method on them and add their results to the set s.update(base.getclassattrset(name)) except AttributeError: # except for the base classes which don't implement this method # (for example the class object) pass return s # returning the collected set def getattrset(self, name): '''Instance method that collects a set of the attributes with a given name from itself, from its class and from all the base classes. The only argument is the name of the attribute to look up; the return value is a list of (class_name, attribute_value) listing all the candidates found. In case the attribute is also found in the object itself, element 0 of the tuple is set to null.''' # saving references to a couple of attributes we need to access # directly, bypassing all this machinery; to achieve it, we # explicitly call object's implementation of __getattribute__ self_dict = object.__getattribute__(self, '__dict__') self_class = object.__getattribute__(self, '__class__') s = set() try: # adding to the set the attribute named name in this very intance, # if it exists, with None in place of the class name s.add((None, self_dict[name])) except KeyError: # unless the instance doesn't have an attribute named name pass # addig to the set all the class attributes named name, from this # object's class and all its base classes s.update(self_class.getclassattrset(name)) return s def __getattribute__(self, name): '''Customized version of attribute fetching, that uses getattrset (and thus getclassattrset) to get a list of all the attributes named name before choosing which one to return.''' # saving references to the attributes we need to access directly self_class = object.__getattribute__(self, '__class__') # calling AttrSearch's getattrset to do the dirty work found = AttrSearch.getattrset(self, name) # here is where you should examine 'found' and choose what to # return; I only print what is available and return None print 'Looking for "%s" in a %s instance, found %d candidates:' \ % (name, self_class.__name__, len(found)) print ' class value' print ' ===== =====' print '\n'.join([ " %-6s '%s'" % x for x in found ]) print '(now choose wisely what to return)' return None # example use of AttrSearch in a class hierarchy: class A(AttrSearch): a = 'attribute "a" of class A' class B(A): a = 'attribute "a" of class B' class C(A): a = 'attribute "a" of class C' class D(B, C): a = 'attribute "a" of class D' t = D() t.a = 'attribute "a" of instance t' # --- end --- Now if you ask for t.a, for example in a print statement, you get None, but not before the following lines are printed to stdout: Looking for "a" in a D instance, found 5 candidates: class value ===== ===== D 'attribute "a" of class D' B 'attribute "a" of class B' A 'attribute "a" of class A' None 'attribute "a" of instance t' C 'attribute "a" of class C' (now choose wisely what to return) HTH Toby PS: I couldn't make out what you meant with your code... I fear it's because of the hideous formatting :-) -- http://mail.python.org/mailman/listinfo/python-list