List of named Python tuples replacing attributes

Here is some simplified code that I do not understand why it does not work.

from collections import namedtuple MyStruct = namedtuple('MyStruct', 'ThreadInstance ThreadName Mnemonic IpAddr IpGW Status Mode') Node = MyStruct(None, '', '', '', '', -1, 0) NodeDb = [] for id in range(4): NodeDb.append(Node) NodeDb[2]._replace(ThreadName='T2') NodeDb[2]._replace(Mnemonic='ABCD') NodeDb[2]._replace(IpAddr='192.0.1.2') NodeDb[2]._replace(IpGW='192.0.1.3') NodeDb[2]._replace(Status=0) NodeDb[2]._replace(Mode=2) print(NodeDb) 

Here is the conclusion

 '>>> [MyStruct(ThreadInstance=None, ThreadName='', Mnemonic='', IpAddr='', IpGW='', Status=-1, Mode=0), MyStruct(ThreadInstance=None, ThreadName='', Mnemonic='', IpAddr='', IpGW='', Status=-1, Mode=0), MyStruct(ThreadInstance=None, ThreadName='', Mnemonic='', IpAddr='', IpGW='', Status=-1, Mode=0), MyStruct(ThreadInstance=None, ThreadName='', Mnemonic='', IpAddr='', IpGW='', Status=-1, Mode=0)]' 
+4
source share
2 answers

_replace does not do what you think. From docs :

somenamedtuple._replace (kwargs)

Return a new instance of the named tuple that replaces the specified fields with the new values:

 >>> p = Point(x=11, y=22) >>> p._replace(x=33) Point(x=33, y=22) 

You call _replace , but you never save the new Node that it returns. The reason that it returns a new object instead of changing the object "in place" is because namedtuples by definition immutable, i.e. They cannot be changed after they are created.

Be aware that your for loop creates a list of four links to the same Node . In this case, this is not a problem, since the objects you create are the same, and namedtuple is immutable, but in general this is known.

So in short:

 from collections import namedtuple MyStruct = namedtuple('MyStruct', 'ThreadInstance ThreadName Mnemonic IpAddr IpGW Status Mode') NodeDb = [] Node = MyStruct(None, '', '', '', '', -1, 0) for id in range(4): NodeDb.append(Node) NodeDb[2] = NodeDb[2]._replace(ThreadName='T2', Mnemonic='ABCD', IpAddr='192.0.1.2', IpGW='192.0.1.3', Status=0, Mode=2) print(NodeDb) 
+7
source

Remember that each item in this list acts as a pointer in C. Python variables are always passed and used by reference. That is, as it is written, this is true:

 assert NodeDb[0] is NodeDb[1] is NodeDb[2] is NodeDb[3] # True 

I think you want to have a list of individual objects, in which case you should move Node = MyStruct(...) inside the for loop.

+1
source

Source: https://habr.com/ru/post/1393036/


All Articles