this Code snippet is namedtuple function of collections module in python.when I see it ,I don't understand it. class_definition is formated string, namespace is dict, exec could code ogject or string and so on, exec class_definition in namespace
how to effect namespace, is that exec generate what?

- 11
- 2
-
2Can you add the code snippet please? – thefourtheye Feb 15 '15 at 07:38
-
I don't mean to be mean, but you should really edit your question and improve the quality of your writing. As it stands, I have trouble understanding what you're saying... – Eithos Feb 15 '15 at 07:39
-
Do you mean the source code for namedtuple in [collections.py](https://hg.python.org/cpython/file/2.7/Lib/collections.py), lines 236-388 ? – PM 2Ring Feb 15 '15 at 07:44
-
@karisankedy Please explain in English. – thefourtheye Feb 15 '15 at 07:52
1 Answers
I am doing this on Python 3, but the principle is the same on Python 2.
Say you are executing
FooBarBaz = namedtuple('FooBarBaz', 'foo bar baz')
In this case, this code
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))
)
uses str.format
to fill in the class template, setting the class_definition
into a string, whose contents are:
class FooBarBaz(tuple):
'FooBarBaz(foo, bar, baz)'
__slots__ = ()
_fields = ('foo', 'bar', 'baz')
def __new__(_cls, foo, bar, baz):
'Create new instance of FooBarBaz(foo, bar, baz)'
return _tuple.__new__(_cls, (foo, bar, baz))
@classmethod
def _make(cls, iterable, new=tuple.__new__, len=len):
'Make a new FooBarBaz object from a sequence or iterable'
result = new(cls, iterable)
if len(result) != 3:
raise TypeError('Expected 3 arguments, got %d' % len(result))
return result
def __repr__(self):
'Return a nicely formatted representation string'
return 'FooBarBaz(foo=%r, 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 FooBarBaz object replacing specified fields with new values'
result = _self._make(map(kwds.pop, ('foo', '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
foo = _property(_itemgetter(0), doc='Alias for field number 0')
bar = _property(_itemgetter(1), doc='Alias for field number 1')
baz = _property(_itemgetter(2), doc='Alias for field number 2')
Now after that the code creates a new dictionary that is used as the global namespace for exec
:
namespace = dict(__name__='namedtuple_%s' % typename)
The reason why we don't use an empty dictionary is that if there is any tracing program that would print out the __name__
of the current module, then it would find __name__
set to namedtuple_FooBarBaz
instead of it not existing.
After that, we execute the class definition, from strings, with global scope as this dictionary.
exec(class_definition, namespace)
Basically this executes the class definition above, which defines a new module global variable FooBarBaz
, which is stored into the namespace
dictionary, which in turn can be fetched there by:
result = namespace[typename] # namespace['FooBarBaz']
now result
is our newly created class; then some wizardry is done for it to survive pickling, after which the class is returned...
and this code again can assign it to the variable FooBarBaz:
FooBarBaz = namedtuple('FooBarBaz', 'foo bar baz')

- 129,958
- 22
- 279
- 321