On Wed, Aug 10, 2011 at 8:48 AM, Fuzzyman <fuzzy...@gmail.com> wrote: > On Aug 7, 4:06 am, Eric Snow <ericsnowcurren...@gmail.com> wrote: >> Thought I knew how to provide a dynamic __name__ on instances of a >> class. My first try was to use a non-data descriptor: >> >> # module base.py >> >> class _NameProxy(object): >> def __init__(self, oldname): >> self.oldname = oldname >> def __get__(self, obj, cls): >> if obj is None: >> return self.oldname >> if "__name__" not in obj.__dict__: >> return str(obj.__context__) >> return obj.__name__ >> >> class _BaseMeta(type): >> def __init__(cls, name, bases, namespace): >> cls.__name__ = _NameProxy(name) >> >> class Base(object): >> __metaclass__ = _BaseMeta >> >> $ python _base.py >> Traceback (most recent call last): >> ... >> File "/usr/local/lib/python2.4/site-packages/base.py", line xx, in __init__ >> cls.__name__ = _NameProxy(name) >> TypeError: Error when calling the metaclass bases >> can only assign string to Base.__name__, not '_NameProxy' >> >> Needless to say I was surprised. After looking in typeobject.c, I >> believe that __name__ must be a string where classes are concerned[1]. >> So if I want all my instances to have a __name__ attribute, and for >> it to be dynamically provided if it isn't set on the instance, what >> are my options? Or maybe I did something wrong and it should work as >> I expected? >> > > __name__ can be a descriptor, so you just need to write a descriptor > that can be fetched from classes as well as instances. > > Here's an example with a property (instance only): > >>>> class Foo(object): > ... @property > ... def __name__(self): > ... return 'bar' > ... >>>> Foo().__name__ > 'bar'
Thanks! Your example is exactly what I didn't try in the first place, but should have. I was thinking of __name__ on a class as a simple data attribute. My original worry was that by adding a descriptor for __name__ on my class, I would overwrite the name of the class, hence the elaborate descriptor. However, for type objects (classes) __name__ is a data descriptor and the actual name isn't stored in __name__. I was staring that right in the face (the link I provided is for the setter method of the __name__ "property" for type objects). I guess it was a "forest for the trees" moment. Because of attribute lookup in Python, "Base.__name__" uses the equivalent of "Base.__class__.__name__.__get__(..., Base, Base.__class__)". Anyway, thanks for making me see how dumb I am! <wink> -eric > > Michael > -- > http://voidspace.org.uk/ > -- > http://mail.python.org/mailman/listinfo/python-list > -- http://mail.python.org/mailman/listinfo/python-list