[Python-Dev] New syntax for 'dynamic' attribute access (original) (raw)

Brett Cannon brett at python.org
Tue Feb 13 21:05:43 CET 2007


On 2/13/07, Nick Coghlan <ncoghlan at gmail.com> wrote:

Taking a step back a bit... the basic issue is that we have an attribute namespace (compile time key determination) that we want to access in a dictionary style (runtime key determination).

This is currently done by switching from syntactic access to the getattr/setattr/delattr builtin functions. Elsewhere in the thread, Calvin made the suggestion that, rather than introducing new syntax, this could instead be achieved with a wrapper class that automatically converted dict-style access into the appropriate calls to getattr/setattr/delattr.

In other words, an object view analagous to what Py3K is doing with keys()/values()/items().

I've tried this out on Brett's urllib & urllib2 examples below. (calling the new builtin attrview() to emphasise the fact that it retains a reference to the original instance). I don't consider it any uglier than the proposed syntax changes, and it provides a few other benefits:

- the two-argument form is naturally available as the .get() method on the resulting dict-like object (e.g. "attrview(obj).get(someattr, None)") - hasattr() is naturally replaced by containment testing (e.g. "someattr in attrview(obj)") - keywords/builtins are easier to look up in the documentation than symbolic syntax

Yeah, the generalization is really nice. It allows use to ditch getattr/setattr/hasattr all without losing the expressiveness of those built-ins.

With this approach, performance would be attained by arranging to create the view objects once, and then performing multiple dynamic attribute accesses using those view objects.

First urllib.py example:: name = 'open' + urltype self.type = urltype name = name.replace('-', '') selfd = attrview(self) if name in selfd: if proxy: return self.openunknownproxy(proxy, fullurl, data) else: return self.openunknown(fullurl, data) try: if data is None: return selfdname else: return selfd[name](url, data) except socket.error, msg: raise IOError, ('socket error', msg), sys.excinfo()[2] Second urllib.py example:: name = 'httperror%d' % errcode selfd = attrview(self) if name in selfd: method = selfd[name] if data is None: result = method(url, fp, errcode, errmsg, headers) else: result = method(url, fp, errcode, errmsg, headers, data) if result: return result return self.httperrordefault(url, fp, errcode, errmsg, headers)

First urllib.py example:: if attr[:12] == 'Request_r': name = attr[12:] getname = 'get' + name if getname in attrview(Request): selfd = attrview(self) selfdgetname return selfd[attr] raise AttributeError, attr Second urllib2.py example:: handlers = chain.get(kind, ()) for handler in handlers: func = attrview(handler)[methname] result = func(*args) if result is not None: return result

I also think it is just as clean as doing it any of the proposed ways::

getattr(self, name) self.[name] attrview(self)[name]

So my vote is for Nick's object attribute view; +1. If we are going to do the view thing, let's go all the way! =)

-Brett



More information about the Python-Dev mailing list