Mutable default argument for a Python namedtuple

python namedtuple with default
python namedtuple as function argument
python namedtuple nullable
mutable default arguments python
python optional arguments none
python dataclass to dict
python default argument empty list
unpack namedtuple

I came across a neat way of having namedtuples use default arguments from here.

from collections import namedtuple
Node = namedtuple('Node', 'val left right')
Node.__new__.__defaults__ = (None, None, None)
Node()

Node(val=None, left=None, right=None)

What would you do if you would want the default value for 'right' to be a empty list? As you may know, using a mutable default argument such as a list is a no no.

Is there a simple way to implement this?

You can't do that that way, because the values in __defaults__ are the actual default values. That is, if you wrote a function that did had someargument=None, and then checked inside the function body with someargument = [] if someargument is None else someargument or the like, the corresponding __defaults__ entry would still be None. In other words, you can do that with a function because in a function you can write code to do whatever you want, but you can't write custom code inside a namedtuple.

But if you want default values, just make a function that has that logic and then creates the right namedtuple:

def makeNode(val=None, left=None, right=None):
    if right is None:
        val = []
    return Node(val, left, right)

Using a mutable default value as an argument, Passing mutable lists or dictionaries as default arguments to a function can have unforeseen consequences. Usually when a programmer uses a list or dictionary​  Motivated by a desire for a mutable namedtuple with default values. To use, subclass, and define __slots__. The default default value is None. To set a default value other than None, set the `default_value` class variable. Example: class Jello(DataObject): default_value = 'no data' __slots__ = ('request_date', 'source_id', 'year', 'group_id', 'color', #

The way given in the accepted answer works great. The only downside I see is that one has to both know (in the case of some other user) and remember to use the factory function instead of the named tuple class- both when creating the object, and when doing things like this:

isinstance(node, Node) #  success
isinstance(node, makeNode) #  misery

A way around this problem might be to do something like what is shown below.

NodeBase = nt('NodeBase', 'val left right')
NodeBase.__new__.__defaults__ = (None, None, None)

class Node(NodeBase):
    '''A namedtuple defined as:

    Node(val, left, right)

    with default values of (None, None, [])'''
    __slots__ = ()
    def __new__(cls, *args, **kwargs):
        obj = super().__new__(cls, *args, **kwargs)
            if obj.right is None:
                obj = obj._replace(right = [])
            return obj

Common Gotchas, Mutable Default Arguments¶. Seemingly the most common surprise new Python programmers encounter is Python's treatment of mutable default arguments in  This is because default arguments of functions and methods are evaluated at definition time rather than run time. So we only ever have a single instance of the li list. The way to get around it is to use only immutable types for default arguments:

Just small change in implementation from Rick Teachey, the default value can be set outside class:

NodeBase = namedtuple('NodeBase', 'val left right')

class Node(NodeBase):
    __slots__ = ()
    def __new__(cls, *, right=[], **kwargs):
        obj = super().__new__(cls, right=[], **kwargs)
        return obj

#IMPLEMENTATION
kw = {'val': 1, 'left':12}

m  = Node(**kw) 
# outputs Node(val=1, left=12, right=[])

Mutable named tuple with default value and conditional rounding , get can take an additional argument for the default value to return. If you change that line to v = kwargs.get(k, v) , then price.update(sale=0)  A named tuple has two required arguments. They are the tuple name and the tuple field_names. In the above example our tuple name was ‘Animal’ and the tuple field_names were ‘name’, ‘age’ and ‘cat’. Namedtuple makes your tuples self-document.

The Ultimate Guide to Data Classes in Python 3.7 – Real Python, How to add default values to data class fields; How data classes allow for In addition to tuple , dict , namedtuple , and attrs , there are many other similar one of the most common anti-patterns in Python: using mutable default arguments. Python’s default arguments are evaluated once when the function is defined, not each time the function is called (like it is in say, Ruby). This means that if you use a mutable default argument and mutate it, you will and have mutated that object for all future calls to the function as well.

Glossary, The default Python prompt of the interactive shell when entering the code for an A label associated with a variable, a class attribute or a function parameter or Example mutable buffer objects include bytearray and a memoryview of a bytearray . The term “named tuple” applies to any type or class that inherits from tuple  Any valid Python identifier may be used for a fieldname except for names starting with an underscore. Valid identifiers consist of letters, digits, and underscores but do not start with a digit or underscore and cannot be a keyword such as class, for, return, global, pass , or raise.

collections — Container datatypes, Changed in version 3.4: The optional m parameter was added. If module is defined, the __module__ attribute of the named tuple is set to that value. SimpleNamespace() for a mutable namespace based on an underlying dictionary instead  A question I answered on Stack Overflow asked for a mutable named tuple.. The naive answer would probably tell them they just want to define a custom object. However, named tuples take up a lot less space than custom objects - unless those objects use __slots__.

Comments
  • Why are you asking for something which you yourself say is a no-no?
  • @John Zwinck: Can we modify __new__() so that it will change a 'None' into a new [] like we do with user defined classes?
  • the downside of this solution is one has to know- or to remember- to actually use the factory function rather than the Node class. this kind of design choice isn't always obvoius.