[Python-Dev] New syntax for 'dynamic' attribute access
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(some_attr,
> None)")
>
> - hasattr() is naturally replaced by containment testing (e.g.
> "some_attr 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('-', '_')
> self_d = attrview(self)
> if name in self_d:
> if proxy:
> return self.open_unknown_proxy(proxy, fullurl, data)
> else:
> return self.open_unknown(fullurl, data)
> try:
> if data is None:
> return self_d[name](url)
> else:
> return self_d[name](url, data)
> except socket.error, msg:
> raise IOError, ('socket error', msg), sys.exc_info()[2]
>
> Second urllib.py example::
>
> name = 'http_error_%d' % errcode
> self_d = attrview(self)
> if name in self_d:
> method = self_d[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.http_error_default(url, fp, errcode, errmsg, headers)
>
>
> First urllib.py example::
>
> if attr[:12] == '_Request__r_':
> name = attr[12:]
> get_name = 'get_' + name
> if get_name in attrview(Request):
> self_d = attrview(self)
> self_d[get_name]()
> return self_d[attr]
> raise AttributeError, attr
>
> Second urllib2.py example::
>
> handlers = chain.get(kind, ())
> for handler in handlers:
> func = attrview(handler)[meth_name]
> 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