Hacker News new | ask | show | jobs
by 4c2383f5c88e911 3210 days ago
It means that if you have a data structure that is represented by a tuple, you can switch the creation call with a namedtuple of the same size, keeping the tuple API, therefore not breaking any older code that may rely on it, while at the same time providing a cleaner interface (using the attribute names) to newer code.

Of course, old code should be upgraded to use attribute names, but it's really convenient to be able to upgrade it painlessy.

2 comments

As a concrete example, in Python 1.5.2, urlparse.py:urlparse returned a 6-element tuple:

  # Parse a URL into 6 components:
  # <scheme>://<netloc>/<path>;<params>?<query>#<fragment>
  # Return a 6-tuple: (scheme, netloc, path, params, query, fragment).
  # Note that we don't break the components up in smaller bits
  # (e.g. netloc is a single string) and we don't expand % escapes.
  def urlparse(url, scheme = '', allow_fragments = 1):
      ...
      tuple = scheme, netloc, url, params, query, fragment
      _parse_cache[key] = tuple
      return tuple
This API was around for years, with people using tuple indexing either explicitly or through destructuring assignment.

This was replaced with a namedtuple. The following is from Python 2.7.10:

  class ParseResult(namedtuple('ParseResult', 'scheme netloc path params query fragment'), ResultMixin):

    __slots__ = ()

    def geturl(self):
        return urlunparse(self)


  def urlparse(url, scheme='', allow_fragments=True):
    """Parse a URL into 6 components:
    <scheme>://<netloc>/<path>;<params>?<query>#<fragment>
    Return a 6-tuple: (scheme, netloc, path, params, query, fragment).
    Note that we don't break the components up in smaller bits
    (e.g. netloc is a single string) and we don't expand % escapes."""
    tuple = urlsplit(url, scheme, allow_fragments)
    scheme, netloc, url, query, fragment = tuple
    if scheme in uses_params and ';' in url:
        url, params = _splitparams(url)
    else:
        params = ''
    return ParseResult(scheme, netloc, url, params, query, fragment)
The old tuple-based API still works, so it doesn't break backwards compatibility, while it also gives people the ability to migrate to an attribute-based API.

That said, it's very hard to remove the old API. The latest version of Python, in url/parse.py:urlparse, still supports tuple-based indexing.

Perhaps Python 4 will remove that behavior? Probably not. At the very least there would need to be a namedtuplemigration type which gives a warning if the old tuple API is used when only attribute lookup is expected.

> This API was around for years, with people using tuple indexing either explicitly or through destructuring assignment.

FWIW destructuring assignment uses the iteration protocol[0] not indexing.

[0] which can fallback on indexing if there is no explicit iteration support, IME that tends to be more unhelpful than convenient

Hmm, I think meant to say something like "using either explicit tuple indexing or through destructuring assignment". Words, mixed up, they were. But yes, what I wrote was wrong.
Thanks for the great answer!