我正在学习namedtuple.我想找到一种方法,使用该._replace方法,更新namedtuple它们所在的所有外观.
假设我有一个节点列表,以及这些节点定义的元素列表(双节点波束,四节点四边形)和边界("一个节点"元素).
我正在玩这个:
from collections import namedtuple as nt
Node = nt('Node', 'x y')
Beam = nt('Beam', 'i j')
Quad = nt('Quad', 'i j k l')
Boundary = nt('Boundary', 'b')
#Define some nodes:
n1 = Node(0,0)
n2 = Node(0,1)
n3 = Node(1,1)
n4 = Node(1,0)
#And some other things using those nodes:
q1 = Quad(n1,n2,n3,n4)
b1 = Boundary(n1)
be1 = Beam(n1,n4)
Run Code Online (Sandbox Code Playgroud)
现在,如果我换成n1新的Node:
n1 = n1._replace(x=0.5,y=0.5)
print(n1) # Node(x=0.5,y=0.5)
Run Code Online (Sandbox Code Playgroud)
其他所有项目均未更新:
print(b1) # Boundary(b=Node(x=0, y=0))
Run Code Online (Sandbox Code Playgroud)
我理解Python命名和对象模型以及这背后的原因:b1.b已经设置为对象 Node(0,0),而不是名称n1.因此,当n1更改时,其他命名元组仍然包含与以前相同的对象,同时n1获取新对象.
我想这样做的是改变这种行为,以便当我改变n1,改变在"感觉" b1,be1,q1,等我怎样才能做到这一点?
所有namedtuple生成的类的实例都是不可变的.._replace()创建一个新实例,它甚至不会更新您调用它的一个实例.
因为实例是不可变的,所以你不能用你想做的事情namedtuple.您必须在子类中提供此类功能,从而有效地破坏了不变性.或者只是提供自己的Node自定义类,允许直接变异属性:
class Node(object):
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return '{0.__class__.__name__}({0.x!r}, {0.y!r})'.format(self)
Run Code Online (Sandbox Code Playgroud)
像a一样namedtuple,这个类__slots__用来减少内存使用.您可以直接在实例上设置x和y属性,对实例的任何其他引用都将看到更改:
>>> class Node(object):
... __slots__ = ('x', 'y')
... def __init__(self, x, y):
... self.x = x
... self.y = y
... def __repr__(self):
... return '{0.__class__.__name__}({0.x!r}, {0.y!r})'.format(self)
...
>>> n1 = Node(10, 20)
>>> n2 = n1
>>> n2
Node(10, 20)
>>> n1.x = 42
>>> n1.y = 81
>>> n2
Node(42, 81)
Run Code Online (Sandbox Code Playgroud)