'How to initialize a NamedTuple child class different ways based on input arguments?

I am building a typing.NamedTuple class (see typing.NamedTuple docs here, or the older collections.namedtuples docs it inherits from) that can accept different ways of being initialized.

Why NamedTuple in this case? I want it to be immutable and auto-hashable so it can be a dictionary key, and I don't have to write the hash function.

I understand that I need to use __new__ rather than __init__ due to NamedTuples being immutable (for example, see this Q&A. I've searched and there are some tidbits out there (e.g. answers to this question on setting up a custom hash for a namedtuple), but I can't get everything working, I'm getting an error about not being able to overwrite __new__.

Here's my current code:

from typing import NamedTuple

class TicTacToe(NamedTuple):
    """A tic-tac-toe board, each character is ' ', 'x', 'o'"""
    row1: str = '   '
    row2: str = '   '
    row3: str = '   '

    def __new__(cls, *args, **kwargs):
        print(f'Enter __new__ with {cls}, {args}, {kwargs}')
        if len(args) == 1 and args[0] == 0:
            new_args = ('   ', '   ', '   ')
        else:
            new_args = args
        self = super().__new__(cls, *new_args, *kwargs)
        return self

if __name__ == '__main__':
    a = TicTacToe(('xo ', 'x x', 'o o'))
    print(a)
    b = TicTacToe(0)
    print(b)

But I'm getting the following error:

Traceback (most recent call last):
  File "c:/Code/lightcc/OpenPegs/test_namedtuple.py", line 4, in <module>
    class TicTacToe(NamedTuple):
  File "C:\Dev\Python37\lib\typing.py", line 1384, 
in __new__
    raise AttributeError("Cannot overwrite NamedTuple attribute " + key)
AttributeError: Cannot overwrite NamedTuple attribute __new__

Am I not able to create a separate __new__ function for a child class that inherits from NamedTuple? It appears from the message that it's attempting to overwrite __new__ for NamedTuple directly, rather than the TicTacToe class.

What's going on here?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source