在Python词典中引用mutable(例如,列表)作为值 - 什么是最佳实践?

时间:2015-06-17 04:25:44

标签: python list dictionary

可以将字典键映射到作为对a的引用的值 可变对象,例如列表。可以通过调用来更改这样的列表对象 一个列表方法对引用,并且更改将反映在 字典。这在以下讨论:

我的问题

将字典键映射到可变的引用好主意吗? 对象而不是将键映射到未命名的值?

换句话说,它 最好用以下方法创建一个字典:

In [74]: x = {'a': somelist}

或:

In [74]: x = {'a': somelist[:]}

最好通过引用该值来更改字典值 通过引用,例如:

In [77]: somelist.remove('apples')

或其字典索引:

In [77]: x['a'].remove('apples')

讨论与研究

引用提供了一个很好的句柄,可以提高a的可读性 功能。然而,据我所知,字典值是这样的事实 一旦创建了值,最初绑定到引用的内容就会丢失;一个人不能 在显示字典时看到这个事实。

另一方面,我不确定这是否重要,因为参考和 value是同一个对象,如果删除了引用,则为value对象 本身仍然存在。

我认为:

In [73]: somelist = ['apples', 'oranges', 'lemons', 'tangerines']
In [74]: x = {'a': somelist}
In [75]: x
Out[75]: {'a': ['apples', 'oranges', 'lemons', 'tangerines']}

在字典x中,键'a'映射到值somelist,但我没有 查看验证该值是否与引用相关联的方法 somelist

In [76]: x['a'] is somelist
Out[76]: True

这确认了我看到的值列表与对象相同 由somelist指出。

In [77]: x['a'].remove('apples')
In [78]: x
Out[78]: {'a': ['oranges', 'lemons', 'tangerines']}

由于字典'a'x的值是一个列表,我可以删除一个项目 从列表中使用对象remove上的列表方法x['a']

In [79]: somelist.remove('lemons')
In [80]: x
Out[80]: {'a': ['oranges', 'tangerines']}

或者,我可以在对象remove上使用方法somelist

In [81]: del somelist

我可以删除对列表的引用,但列表对象本身仍然存在 作为与键a相关联的值。

In [82]: x['a'].remove('oranges')

In [83]: x
Out[83]: {'a': ['tangerines']}

2 个答案:

答案 0 :(得分:3)

据我了解你的问题,答案是它取决于你想做什么。如果要将字典值设置为某个其他值的独立副本,请进行复制。如果要将其设置为同一个对象,则不要复制。

在某些情况下,您可能希望字典引用与其他引用相同的对象,因为这允许字典“看到”对该对象的更改。在某些情况下,您可能希望字典具有自己的副本,因为您不希望其他更改对象的代码影响您的字典。它只取决于可变对象的内容以及整个代码如何使用它。

答案 1 :(得分:0)

首先,可以在字典中使用可变值。这不是反模式。如果您不需要来复制列表,那么请不要。这是额外的工作,所以要懒惰,不要这样做。

其次,虽然有些情况下我有两个引用可变对象的引用,但这些似乎很少见。我认为你想要最小化这些情况的数量,因为在同一范围内指向同一对象的两个不同的名称可能可能令人困惑。但如果你有x['a']function drawLine(toX, toY, context,type) { if (type == "line") { context.strokeStyle = "#FF0000"; context.beginPath(); context.moveTo((startX), (startY)); context.lineTo((toX), (toY)); context.stroke(); } else if (type == "circle") { context.strokeStyle = "#FF0000"; context.beginPath(); context.moveTo(startX, startY + (toY - startY) / 2); context.bezierCurveTo(startX, startY, toX, startY, toX, startY + (toY - startY) / 2); context.bezierCurveTo(toX, toY, startX, toY, startX, startY + (toY - startY) / 2); context.closePath(); context.stroke(); } else if (type == "rect") { context.beginPath(); context.rect(startX, startY, mouseX - startX, mouseY - startY); context.strokeStyle = '#FF0000'; context.stroke(); } } 指向同一个对象,请使用最清楚的对象。前者将更快,但不是很多,并且除非以紧密循环书写,否则不会是巨大的速度提升。那么选择读取最好的东西。