This is the 13th day of my participation in Gwen Challenge

Today I introduced a handy little function in Collections: the namedtuple function (which can have the convenience of a class without creating it), for example using object.attribute

Look at the demo

Access properties like a class

from collections import namedtuple

Friend = namedtuple('Friend'['name'.'gender'.'address'.'star'.'signature'])

RidingRoad = Friend('RidingRoad'.'male'.'Mars'.'The five-star high praise'.'Change the world by Program! \n'
                    'Do what you like! \n'
                    'Live what you want! ')

print(RidingRoad.name)
print(RidingRoad.gender)
print(RidingRoad.address)
print(RidingRoad.star)
print(RidingRoad.signature)
Copy the code
RidingRoad
male
Mars
The five-star high praise
Change the world by Program!
Do what you like!
Live what you want!
Copy the code

Dictionary-like access

Access items, keys, and values like a dictionary

for key, value in RidingRoad.__dict__.items():
    print(key, value)

print("*" * 30)

for key in RidingRoad.__dict__.keys():
    print('{} :.format(key), eval('RidingRoad.{}'.format(key)))

print("*" * 30)

for value in RidingRoad.__dict__.values():
    print(value)
Copy the code
('name', 'RidingRoad') ('gender', 'male') ('address', 'Mars') ('star', 'The five-star high praise') ('signature', 'Change the world by Program! \nDo what you like! \nLive what you want! ') ****************************** ('name: ', 'RidingRoad') ('gender: ', 'male') ('address: ', 'Mars') ('star: ', 'The five-star high praise') ('signature: ', 'Change the world by Program! \nDo what you like! \nLive what you want! ') ****************************** RidingRoad male Mars The five-star high praise Change the world by Program! Do what you like! Live what you want!Copy the code

Why is that possible?

At this point, you should have two questions:

  1. Why is there a class shadow?
  2. Why is there a shadow of a dictionary?

The source code parsing

Why is there a class shadow?

Look at the _class_template section of the source code, in fact, the function creates a class for us

# Fill-in the class template
    class_definition = _class_template.format(
        typename = typename,
        field_names = tuple(field_names),
        num_fields = len(field_names),
        arg_list = repr(tuple(field_names)).replace("'"."") [1: -1],
        repr_fmt = ', '.join(_repr_template.format(name=name)
                             for name in field_names),
        field_defs = '\n'.join(_field_template.format(index=index, name=name)
                               for index, name in enumerate(field_names))
    )
    if verbose:
        print class_definition
Copy the code

And then what does _class_template do? Define the class

_class_template = '''\ class {typename}(tuple): '{typename}({arg_list})' __slots__ = () _fields = {field_names! r} def __new__(_cls, {arg_list}): 'Create new instance of {typename}({arg_list})' return _tuple.__new__(_cls, ({arg_list})) @classmethod def _make(cls, iterable, new=tuple.__new__, len=len): 'Make a new {typename} object from a sequence or iterable' result = new(cls, iterable) if len(result) ! = {num_fields:d}: raise TypeError('Expected {num_fields:d} arguments, got %d' % len(result)) return result def __repr__(self): 'Return a nicely formatted representation string' return '{typename}({repr_fmt})' % 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 {typename} object replacing specified fields with new values' result = _self._make(map(kwds.pop, {field_names! r}, _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 {field_defs} '''
Copy the code

Why is there a shadow of a dictionary?

Look at the _asdict section of the source code, which encapsulates ordered dictionaries, so we can access dictionary features through __dict__

__dict__ = _property(_asdict)
 def _asdict(self) :
        'Return a new OrderedDict which maps field names to their values'
        return OrderedDict(zip(self._fields, self))
Copy the code