namedtuple fields with default values

I'm using a namedtuple to keep track of several fields, only some of which ever need to be specified during instantiation. However, there is no Pythonic way to create a namedtuple with fields that have default values.
If you do want default parameters for a namedtuple, the workaround right now involves modifying Foo.__new__'s defaults:
Foo = namedtuple('Foo', ['bar', 'optional_baz']) Foo.__new__.__defaults__ = (None, None)
Then you can call Foo's constructor without specifying each field:
Having to assign to Foo.__new__.__defaults__ is a bit ugly. I think it would be easier and more readable to support syntax like:
Foo = namedtuple('Foo', ['optional_bar=None', 'optional_baz=None'])
This suggestion is fully backwards compatible and allows for cleaner definitions of nametuples with default-value fields. Thanks for considering. Russell

On Jul 16, 2015, at 01:03 PM, Russell Kaplan wrote:
I don't know about "Pythonic" but there's a not too horrible way to do it: _Record = namedtuple('Record', 'url destination checksum')('', '', '') def Record(url, destination, checksum=''): return _Record._replace( url=url, destination=destination, checksum=checksum) Now you only need to provide 'url', and 'destination' when you create a Record. Okay, sure _Record is the actual namedtuple, but I usually don't care.
That would mean you couldn't ever have an actual parameter called 'optional_bar'.
This suggestion is fully backwards compatible and allows for cleaner definitions of nametuples with default-value fields. Thanks for considering.
Not that I think anything really needs to be done, but a few other approaches could be: * Allow for arbitrary keyword arguments at the end of the signature to define default values. Record = namedtuple('Record', 'url destination checksum', checksum='') * Extend the semantics of field_names to allow for a dictionary of attributes mapping to their default values, though you'd need a marker to be able to specify a required field: Record = namedtuple('Record', dict(url=Required, destination=Required, checksum='')) I suppose I'd prefer the former, although that might cut off the ability to add other controlling arguments to the namedtuple() API. Cheers, -Barry

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 07/17/2015 10:44 AM, Barry Warsaw wrote:
I've implemented default parameters to namedtuples (and namedlists a mutable version) in https://pypi.python.org/pypi/namedlist The syntax is not great, but none of the options are awesome.
Point = namedlist.namedtuple('Point', [('x', 0), ('y', 100)]) p = Point() assert p.x == 0 assert p.y == 100
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.14 (GNU/Linux) iQEcBAEBAgAGBQJVqRg5AAoJENxauZFcKtNxLSYH/iC2Twf2xYhAbtKdMF7nSvG2 xOhhePDOBWl4K9cUVgg0z4jRsnGgL8O8FPCGVmsrBu8arseVAQbsFiAcOsmlKy3k XZGYQ61KPlDUcqxIO661cOWDiRJG/I9ltQHlafODEs4qGJfox2BeM5aCo+cIpyhk uC7wJ/t9mJ9uKvv6mG/e1GixzKtgcCO86NfYwIqiwaZWsKnjkqNzQ1peKm6pGRTK 34u7oCu6EGbqNCUdAJx9Re6Umcs37FH/f3uyc2luJyP9z1p1zz2Ndb00NwOvsGKK NJw5enVB6/qC+sGZDicE1lJmij/MwdTbu/+Fl+JxjZeMGeRWJ9PEyHaxmuZAzw8= =ZXBa -----END PGP SIGNATURE-----

FWIW, PEP 484 (and hence typing.py) uses this syntax with a different meaning: * NamedTuple, used as ``NamedTuple(type_name, [(field_name, field_type), ...])`` and equivalent to ``collections.namedtuple(type_name, [field_name, ...])``. This is useful to declare the types of the fields of a a named tuple type. On Fri, Jul 17, 2015 at 4:59 PM, Eric V. Smith <eric@trueblade.com> wrote:
-- --Guido van Rossum (python.org/~guido)

On Fri, 17 Jul 2015 10:44:15 -0400 Barry Warsaw <barry@python.org> wrote:
My usual pattern is to subclass the namedtuple class and override the constructor (especially if I want to add behaviour): class Record(namedtuple('_Record', ('url', 'dest', 'checksum'))): __slots__ = () def __new__(...): #etc Regards Antoine.

The problem of subclassing is the somewhat tedious repetition in the argument list of __new__. You can abuse the fact that function definition allows you to 1. create an object who knows its name and 2. list arguments, with or without default values to write a decorator @Namedtuple, such that @Namedtuple def Record(foo, bar=default): pass (I have an implementation but it's nothing really special, just introspecting the signature object.) Antony 2015-07-17 8:33 GMT-07:00 Antoine Pitrou <solipsis@pitrou.net>:

On Jul 16, 2015, at 01:03 PM, Russell Kaplan wrote:
I don't know about "Pythonic" but there's a not too horrible way to do it: _Record = namedtuple('Record', 'url destination checksum')('', '', '') def Record(url, destination, checksum=''): return _Record._replace( url=url, destination=destination, checksum=checksum) Now you only need to provide 'url', and 'destination' when you create a Record. Okay, sure _Record is the actual namedtuple, but I usually don't care.
That would mean you couldn't ever have an actual parameter called 'optional_bar'.
This suggestion is fully backwards compatible and allows for cleaner definitions of nametuples with default-value fields. Thanks for considering.
Not that I think anything really needs to be done, but a few other approaches could be: * Allow for arbitrary keyword arguments at the end of the signature to define default values. Record = namedtuple('Record', 'url destination checksum', checksum='') * Extend the semantics of field_names to allow for a dictionary of attributes mapping to their default values, though you'd need a marker to be able to specify a required field: Record = namedtuple('Record', dict(url=Required, destination=Required, checksum='')) I suppose I'd prefer the former, although that might cut off the ability to add other controlling arguments to the namedtuple() API. Cheers, -Barry

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 07/17/2015 10:44 AM, Barry Warsaw wrote:
I've implemented default parameters to namedtuples (and namedlists a mutable version) in https://pypi.python.org/pypi/namedlist The syntax is not great, but none of the options are awesome.
Point = namedlist.namedtuple('Point', [('x', 0), ('y', 100)]) p = Point() assert p.x == 0 assert p.y == 100
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.14 (GNU/Linux) iQEcBAEBAgAGBQJVqRg5AAoJENxauZFcKtNxLSYH/iC2Twf2xYhAbtKdMF7nSvG2 xOhhePDOBWl4K9cUVgg0z4jRsnGgL8O8FPCGVmsrBu8arseVAQbsFiAcOsmlKy3k XZGYQ61KPlDUcqxIO661cOWDiRJG/I9ltQHlafODEs4qGJfox2BeM5aCo+cIpyhk uC7wJ/t9mJ9uKvv6mG/e1GixzKtgcCO86NfYwIqiwaZWsKnjkqNzQ1peKm6pGRTK 34u7oCu6EGbqNCUdAJx9Re6Umcs37FH/f3uyc2luJyP9z1p1zz2Ndb00NwOvsGKK NJw5enVB6/qC+sGZDicE1lJmij/MwdTbu/+Fl+JxjZeMGeRWJ9PEyHaxmuZAzw8= =ZXBa -----END PGP SIGNATURE-----

FWIW, PEP 484 (and hence typing.py) uses this syntax with a different meaning: * NamedTuple, used as ``NamedTuple(type_name, [(field_name, field_type), ...])`` and equivalent to ``collections.namedtuple(type_name, [field_name, ...])``. This is useful to declare the types of the fields of a a named tuple type. On Fri, Jul 17, 2015 at 4:59 PM, Eric V. Smith <eric@trueblade.com> wrote:
-- --Guido van Rossum (python.org/~guido)

On Fri, 17 Jul 2015 10:44:15 -0400 Barry Warsaw <barry@python.org> wrote:
My usual pattern is to subclass the namedtuple class and override the constructor (especially if I want to add behaviour): class Record(namedtuple('_Record', ('url', 'dest', 'checksum'))): __slots__ = () def __new__(...): #etc Regards Antoine.

The problem of subclassing is the somewhat tedious repetition in the argument list of __new__. You can abuse the fact that function definition allows you to 1. create an object who knows its name and 2. list arguments, with or without default values to write a decorator @Namedtuple, such that @Namedtuple def Record(foo, bar=default): pass (I have an implementation but it's nothing really special, just introspecting the signature object.) Antony 2015-07-17 8:33 GMT-07:00 Antoine Pitrou <solipsis@pitrou.net>:
participants (6)
-
Antoine Pitrou
-
Antony Lee
-
Barry Warsaw
-
Eric V. Smith
-
Guido van Rossum
-
Russell Kaplan