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)
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
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
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.
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')])
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)
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'
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)
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
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
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.
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')])
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)
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'