Last active
November 24, 2017 17:52
-
-
Save homecoder/9f37ed975e9a5f4961f0290137d70e70 to your computer and use it in GitHub Desktop.
Named Tuple configurable defaults
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Based on code found @ https://stackoverflow.com/a/18348004/7513482 | |
import collections | |
import sys | |
def namedtuple_with_defaults(typename, field_names, default_values=(), verbose=False, rename=False, module=None): | |
""" | |
Create a namedtuple object with customizable defaults. | |
Returns a new tuple subclass named typename | |
:param typename: Name of the tuple subclass created | |
:param field_names: (str): Space separated list of class attributes | |
:param default_values: (dict,list,tuple): Setup default values | |
:param verbose: (bool): Print class definition after build. Outdated, use _source instead. | |
:param rename: Automatically rename invalid fieldnames (i.e. 'def') to positional arguments rather than fail. | |
:param module: If module is defined, the __module__ attribute of the named tuple is set to that value. | |
:return: typename(tuple) | |
Note: If you wish to see the source, call print(Friend._source) after examples below from python interpreter. | |
""" | |
opts = {'verbose': verbose, 'rename': rename, 'module': module} | |
# Fix for Python < 3.6, < 3.1 | |
py_version = int(''.join(map(str, sys.version_info[:2]))) # Python 2.7 becomes 27, 3.5 = 35, etc. | |
if py_version < 31: | |
# Verbose option was added in 3.1 | |
opts = {'verbose': verbose, 'rename': rename} | |
elif py_version < 36: | |
# Module was added in 3.6 | |
del opts['module'] | |
T = collections.namedtuple(typename, field_names, **opts) | |
T.__new__.__defaults__ = (None,) * len(T._fields) | |
if isinstance(default_values, collections.Mapping): | |
prototype = T(**default_values) | |
else: | |
prototype = T(*default_values) | |
T.__new__.__defaults__ = tuple(prototype) | |
return T | |
# Example: | |
Friend = namedtuple_with_defaults('Friend','first_name last_name email_address favourite_module least_favourite_module',rename=True,verbose=True) | |
example1 = Friend(first_name='Guido', last_name='van Rossum', favourite_module='helpista', least_favourite_module=None) | |
print(example1) | |
# Output: Friend(first_name='Guido', last_name='van Rossum', email_address=None, favourite_module='helpista', least_favourite_module=None) | |
# Example 2 | |
example2 = RubyFriend(first_name='Guido', last_name='van Rossum', favourite_module='Rails', least_favourite_module=None) | |
# Uh oh, an error! | |
Traceback (most recent call last): | |
# ... blah blah blah | |
TypeError: __new__() missing 1 required positional argument: 'email_address' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment