Skip to content

Instantly share code, notes, and snippets.

@solidsnack
Last active August 29, 2015 14:28
Show Gist options
  • Select an option

  • Save solidsnack/76ce7f4ae91e589774cc to your computer and use it in GitHub Desktop.

Select an option

Save solidsnack/76ce7f4ae91e589774cc to your computer and use it in GitHub Desktop.
Namedtuple annotation for Python -- derive namedtuple definition from the signature of __init__()!
"""Namedtuple annotation.
Creates a namedtuple out of a class, based on the signature of that class's
__init__ function. Defaults are respected. After namedtuple's initializer is
run, the original __init__ is run as well, allowing one to assign synthetic
parameters and internal book-keeping variables. (Note that the original
__init__ may not assign to the variables in its signature, because these
variables are made immutable by namedtuple).
The class must not have varargs or keyword args.
Thanks to @mjpieters: http://stackoverflow.com/a/32171046/48251
"""
import collections
import inspect
def namedtuple(cls):
argspec = inspect.getargspec(cls.__init__)
assert argspec.varargs is None
assert argspec.keywords is None
non_self_args = argspec.args[1:]
# Now we can create the new class definition, based on a namedtuple.
bases = (collections.namedtuple(cls.__name__, non_self_args), cls)
namespace = {'__doc__': cls.__doc__}
newcls = type(cls.__name__, bases, namespace)
# Here we set up the new class's __new__, which hands off to namedtuple's
# after setting defaults.
@staticmethod
def new(*args, **kwargs):
kls = args[0]
# Resolve default assignments with this utility from inspect.
values = inspect.getcallargs(cls.__init__, None, *args[1:], **kwargs)
values = [values[_] for _ in non_self_args]
obj = super(newcls, kls).__new__(kls, *values)
cls.__init__(obj, *values) # Allow initialization to occur
return obj
newcls.__new__ = new
return newcls
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment