Raymond Hettinger wrote:
The constructor signature has been experimented with several time and had best results in its current form which allows the *args for casting a record set returned by SQL or by the CSV module as in Point(*fetchall(s)),
I think you mean something like [Point(*tup) for tup in fetchall(s)], which I don't like for the reasons explained later.
and it allows for direct construction with Point(2,3) without the slower and weirder form: Point((2,3)). Also, the current signature works better with keyword arguments: Point(x=2, y=3) or Point(2, y=3) which wouldn't be common but would be consistent with the relationship between keyword arguments and positional arguments in other parts of the language.
I don't buy this argument. Yes, Point(2,3) is nicer than Point((2,3)) in the interactive interpreter and in the doctests, but in real life one has always tuples coming as return values from functions. Consider your own example, TestResults(*doctest.testmod()). I will argue that the * does not feel particularly good and that it would be better to just write TestResults(doctest.testmod()). Moreover I believe that having a subclass constructor incompatible with the base class constructor is very evil. First of all, you must be consistent with the tuple constructor, not with "other parts of the language". Finally I did some timing of code like this::
from itertools import imap Point = namedtuple('Point x y'.split())
lst = [(i, i*i) for i in range(500)]
def with_imap(): for _ in imap(Point, lst): pass
def with_star(): for _ in (Point(*t) for t in lst): pass
and as expected the performances are worse with the * notation. In short, I don't feel any substantial benefit coming from the *args constructor.
The string form for the named tuple factory was arrived at because it was easier to write, read, and alter than its original form with a list of strings: Contract = namedtuple('Contract stock strike volatility expiration rate iscall') vs. Contract = namedtuple('Contract', 'stock', 'strike', 'volatility', 'expiration', 'rate', 'iscall') That former is easier to edit and to re-arrange. Either form is trivial to convert programmatically to the other and the definition step only occurs once while the use of the new type can appear many times throughout the code. Having experimented with both forms, I've found the string form to be best thought it seems a bit odd. Yet, the decision isn't central to the proposal and is still an open question.
``Contract = namedtuple('Contract stock strike volatility expiration rate iscall'.split())`` is not that bad either, but I agree that this is a second order issue.