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?
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.
@Antimony: pickle handles namedtuple classes just fine; classes defined in a function local namespace not so much.
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).
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.
It's not pretty:
p = Person(*(dict(name='joe', age=25)[k] for k in Person._fields))
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With