Python mutable NamedTuple

Question:

I am looking for a struct like data structure I can create multiple instances from and have some type hinting without being immutable.

So I have something like this:

class ConnectionConfig(NamedTuple):
    name: str
    url: str
    port: int
    user: str = ""
    pwd: str = ""
    client: Any = None

But I would like to have it mutable. I could do it like that:

class ConnectionConfig():
    def __init__(self, name: str, url: str, port: int, user: str = "", pwd: str = "", client: Any = None):
        self.name = name
        self.url = url
        self.port = port
        self.user = user
        self.pwd = pwd
        self.client = client

But man… that is ugly :/ Are there any built-in alternatives in python? (using Python 3.6.3)

Asked By: Jodo

||

Answers:

class ConnectionConfig():
    name: str
    url: str
    port: int
    user: str = ""
    pwd: str = ""
    client: Any = None
    def __init__(self, **kv):
        self.__dict__.update(kv)

then you can specify everything in the constructor

c=ConnectionConfig(port=22)

print (c.port)  # will print 22
Answered By: gambuzzi

How about using recordclass (pip install recordclass)?

from recordclass import recordclass


>>> Point = recordclass('Point', 'x y')

>>> p = Point(3, 2)
>>> p
Point(x=3, y=2)
>>> p.x = 8

It’s (nearly) the same api as namedtuple and it’s mutable

Answered By: maor10

Your implementation is quite the (only) built-in way to do it, actually:

class ConnectionConfig():
    def __init__(self, name: str, url: str, port: int, user: str = "",
                 pwd: str = "", client: Any = None):
        pass

Reading PEP 0484 I haven’t found any other alternatives that fit your needs. Continuing the PEP chain, I guess this quote from PEP 20 The Zen of Python explains it:

There should be one– and preferably only one –obvious way to do it.

Answered By: viddik13

Calling “_asdict()” on creation of the NamedTuple will transform it to an OrderedDict(), but not really satisfying at all…

from typing import NamedTuple

class ConnectionConfig(NamedTuple):
    name: str
    url: str
    port: int
    user: str = ""
    pwd: str = ""

mutable_connection_cfg = ConnectionConfig("my_name", "my_url", 111, "my_user", "my_pwd")._asdict()

print(mutable_connection_cfg)
>> OrderedDict([('name', 'my_name'), ('url', 'my_url'), ('port', 111), ('user', 'my_user'), ('pwd', 'my_pwd')])
Answered By: Jodo

There is a compact solution on the base of recordclass library:

> pip3 install recordclass

from recordclass import dataobject

class ConnectionConfig(dataobject):
    name: str
    url: str
    port: int
    user: str = ""
    pwd: str = ""
    client: Any = None

>>> con = ConnectionConfig('name','url',8080,'user','secret',tcp_client)

>>> sys.getsizeof(con)
108   # PyHEAD (16) + 6*sizeof(*void) bytes

If one want faster instance creation there is an option:

class ConnectionConfig(dataobject, fast_new=True):
    name: str
    url: str
    port: int
    user: str = ""
    pwd: str = ""
    client: Any = None

(Note: that this one could be less comfortable with IDE editor’s autocompletion)

Another option:

>>> from recordclass import make_dataclass
>>> ConnectionConfig = make_dataclass(
          "ConnectionConfig",
          [('name',str), ('url',str), ('port',str), 
           ('use',str), ('pwd',str), ('client',Any)],
          defaults=(None,), 
          fast_new=True)
Answered By: intellimath

You can use the pass statement.

class myclass: pass

Then you can create the attributes just before using them:

myclass.a=0
myclass.b='string'
Answered By: David