On 31 December 2015 at 11:30, Charles T. Smith <cts.private.ya...@gmail.com> wrote: >>> Obviously there is a syntax difference between x.attr and x['key'] >> >> Not merely syntax; the attributes of an object are not generally >> available as items of the container. > > > What are the set of ways that an attribute is accessible? Including > implementation implications? > > >> >>> Either the instance __dict__, the class __dict__, or a superclass >>> __dict__. >> >> No, I'm not referring to the ‘__dict__’ attribute of an object; I'm >> referring to the object itself. >> >> To talk about the attributes of an object ‘foo’ is distinct from talking >> about the items in a dictionary ‘foo’. That distinction is real, and >> important. > > > But wanting to deal with the attributes of an object without considering > the way it's implemented - although possible - requires a complete virtual > model that covers all implications. It's easier to simply understand how the > objects work under the covers.
When you write x.attr the name 'attr' is looked up on the object x. This calls x.__getattribute__('attr'). In turn this checks the dict associated with the object x i.e. x.__dict__['attr']. This in turn calls x.__dict__.__getitem__('attr'). The lookup of x.__dict__ is special and doesn't use the normal __getattribute__ mechanism (otherwise this would be an infinite recursion). Generally special attributes (with double underscores) are looked up in a different way. If x.__dict__ does not have the attribute then the dict associated with the class/type of x is checked i.e. x.__class__.__dict__['attr']. The lookup of x.__class__ is also special. Failing this the other classes in x.__class__.__mro__ are checked i.e. x.__class__.__mro__[1].__dict__['attr']. Once these are exhausted x.__getattribute__('attr') falls back on calling x.__getattr__('attr'). IIUC you're trying to create an attribute dict where the same attributes can be looked up via x.attr or x['attr'] (i.e. x.__getattribute__('attr') or x.__getitem__('attr')). One way to do this is to subclass dict and then set each instances __dict__ to be itself. This way __getattribute__ will search the instance (which is a dict subclass) as its own attribute dict. You can then use __getattr__ as the fallback for attributes that are not found. A simple implementation of this could look like: class attrdict(dict): def __init__(self, name=None): self.__dict__ = self kwargs = {'name':name} if name is not None else {} super(attrdict, self).__init__(**kwargs) def __getattr__(self, attrname): ob = self[attrname] = type(self)(name=attrname) return ob >>> d = attrdict('foo') >>> d {'name': 'foo'} >>> d.bar {'name': 'bar'} >>> d {'bar': {'name': 'bar'}, 'name': 'foo'} The problem with this as with any dict subclass approach is that a dict has a load of methods (.items() .keys() .pop() ...) that will now become conflated with your dict keys when you use the attribute access: >>> d.items <built-in method items of attrdict object at 0x7f2025eab868> This means that you can't use any of the dict method names in whatever you're doing. This is the reason that a dict uses a different mechanism __getitem__ so that it can store arbitrary keys at the same time as having named methods which must be attributes. Personally I think that the best approach is to ditch the idea of conflating attributes and keys and just use the subscript x['attr'] syntax. -- Oscar -- https://mail.python.org/mailman/listinfo/python-list