[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