Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make namedtuple accept kwargs

If I have a class like:

class Person(object):
    def __init__(self, name, **kwargs):
        self.name = name

p = Person(name='joe', age=25) # age is ignored

Extra params are ignored. But if I have a namedtuple, I'll get `unexpected keyword argument:

from collections import namedtuple 

Person = namedtuple('Person', 'name')
p = Person(name='joe', age=25)

# Traceback (most recent call last):
#   File "python", line 1, in <module>
# TypeError: __new__() got an unexpected keyword argument 'age'

How can I make namedtuple accept kwargs so I can pass extra arguments safely?

like image 338
Sam R. Avatar asked Mar 01 '16 15:03

Sam R.


People also ask

Can Namedtuple have methods?

count() and . index() , namedtuple classes also provide three additional methods and two attributes. To prevent name conflicts with custom fields, the names of these attributes and methods start with an underscore. In this section, you'll learn about these methods and attributes and how they work.

Can Namedtuple be pickled?

@Antimony: pickle handles namedtuple classes just fine; classes defined in a function local namespace not so much.

Is Namedtuple fast?

NamedTuple is the faster one while creating data objects (2.01 µs). An object is slower than DataClass but faster than NamedTuple while creating data objects (2.34 µs).

How do I change Namedtuple value?

Since a named tuple is a tuple, and tuples are immutable, it is impossible to change the value of a field. In this case, we have to use another private method _replace() to replace values of the field. The _replace() method will return a new named tuple.


2 Answers

It's not pretty:

p = Person(*(dict(name='joe', age=25)[k] for k in Person._fields))
like image 175
PaulMcG Avatar answered Sep 24 '22 03:09

PaulMcG


The following session in the interpreter shows one possible solution to fixing your problem:

Python 3.5.0 (v3.5.0:374f501f4567, Sep 13 2015, 02:27:37) [MSC v.1900 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> import collections
>>> class Person(collections.namedtuple('base', 'name')):
    __slots__ = ()
    def __new__(cls, *args, **kwargs):
        for key in tuple(kwargs):
            if key not in cls._fields:
                del kwargs[key]
        return super().__new__(cls, *args, **kwargs)


>>> p = Person(name='joe', age=25)
>>> p
Person(name='joe')
>>> 

Alternative:

Since you rather have a simpler solution, you might find the next program more to your liking:

#! /usr/bin/env python3
import collections


def main():
    Person = namedtuple('Person', 'name')
    p = Person(name='joe', age=25)
    print(p)


def namedtuple(typename, field_names, verbose=False, rename=False):
    base = collections.namedtuple('Base', field_names, verbose, rename)
    return type(typename, (base,), {
        '__slots__': (),
        '__new__': lambda cls, *args, **kwargs: base.__new__(cls, *args, **{
            key: value for key, value in kwargs.items()
            if key in base._fields})})


if __name__ == '__main__':
    main()
like image 43
Noctis Skytower Avatar answered Sep 23 '22 03:09

Noctis Skytower