Reputation: 87
The documentation says that any python valid identifier can be a field_name, except those which start with underscore, that's fine.
If the rename
argument is true, it replaces invalid field_names with valid ones, but in the example specified there, it replaces it with _1
, or _3
, how is that? These start with underscore!
The documentation also says:
If verbose is true, the class definition is printed just before being built
What does this really mean?
Upvotes: 3
Views: 2320
Reputation: 1121058
The reason you cannot use underscores at the start of names is that there is a chance these would clash with the method names the class provides (such as _replace
).
Because just numbers are not valid Python names, any name not valid as an attribute (so not a valid Python identifier or a name starting with an underscore) are replaced by underscore + position number. This means these generated names cannot clash with valid names nor with the provided methods on the type.
This is not inconsistent with what names you are allowed to pick; it is in fact the perfect fallback given the restrictions. In addition, the name thus generated is easily deduced; the attribute for such values is directly related to their index in the tuple.
As for setting verbose
to True
, it does what it says on the tin. The source code of the generated namedtuple
class is printed to sys.stdout
:
>>> from collections import namedtuple
>>> namedtuple('foo', 'bar baz', verbose=True)
class foo(tuple):
'foo(bar, baz)'
__slots__ = ()
_fields = ('bar', 'baz')
def __new__(_cls, bar, baz):
'Create new instance of foo(bar, baz)'
return _tuple.__new__(_cls, (bar, baz))
@classmethod
def _make(cls, iterable, new=tuple.__new__, len=len):
'Make a new foo object from a sequence or iterable'
result = new(cls, iterable)
if len(result) != 2:
raise TypeError('Expected 2 arguments, got %d' % len(result))
return result
def __repr__(self):
'Return a nicely formatted representation string'
return 'foo(bar=%r, baz=%r)' % self
def _asdict(self):
'Return a new OrderedDict which maps field names to their values'
return OrderedDict(zip(self._fields, self))
def _replace(_self, **kwds):
'Return a new foo object replacing specified fields with new values'
result = _self._make(map(kwds.pop, ('bar', 'baz'), _self))
if kwds:
raise ValueError('Got unexpected field names: %r' % kwds.keys())
return result
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return tuple(self)
__dict__ = _property(_asdict)
def __getstate__(self):
'Exclude the OrderedDict from pickling'
pass
bar = _property(_itemgetter(0), doc='Alias for field number 0')
baz = _property(_itemgetter(1), doc='Alias for field number 1')
<class '__main__.foo'>
This lets you inspect what exactly was generated for your class.
Upvotes: 4