Pergunta

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?

Foi útil?

Solução

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top