Python:更新参考值

时间:2014-09-17 20:56:39

标签: python pointers dictionary reference mutability

以下是我认为的应该如何:

dictionary = {'k1': {'a': 'b'}, 'k2': [0, 1]}  
pointer = dictionary['k1']  
print pointer  
>>> {'a': 'b'}  
pointer.update({'a': 'c'})  
print dictionary  
>>> {'k1': {'a': 'c'}, 'k2': [0, 1]} 

以下让我感到沮丧:

pointer = dictionary['k2']
print pointer
>>> [0, 1]
pointer.update([2, 3])
>>> AttributeError: 'list' object has no attribute 'update'  

我知道列表没有更新功能并且理解我可以做类似的事情:

pointer[0] = 2

...但我希望有一个更通用的选项来更新参考值,因此该对象仍属于字典,但值已更改。

这是因为我有一个看起来像这样的嵌套字典:

dictionary['key']['key']['key']['key'] 

我的问题不在于列表是否具有更新功能 - 而是我在询问是否有更清晰的方法来引用和更改深层嵌套字典中的值所以它会更好在眼睛上将其存储在参考值中,而不是每次我想要为其分配内容时都将其全部输入。

谢谢!

编辑:修正了第一个例子中的语法
编辑2:让我说清楚:我知道列表没有update功能,而是我要求通用参考值更新
EDIT3:简化问题

4 个答案:

答案 0 :(得分:3)

从错误消息中可以明显看出,list没有update方法。这并不意味着你无法改变其内容,你只需要以不同的方式去做。

pointer[:] = [2, 3]

可以制作通用更新功能,但我不确定它会有多大用处。

def update(pointer, values):
    if isinstance(pointer, list):
        pointer[:] = values
    else:
        pointer.update(dict(values))

编辑:看来你真的只对更新叶子节点感兴趣,所以我不明白为什么以下内容不够。只要pointer设置为可变对象,您就可以更改该对象,并且它也会在原始字典中更改。您无法做的唯一事情是直接重新分配,因为它会重新分配引用并断开与字典的连接。

pointer = dictionary['key1']['key2']['key3']['key4']
# pointer = [2, 3]   # doesn't work
pointer[:] = [2, 3]  # works
print dictionary['key1']['key2']['key3']['key4']

答案 1 :(得分:3)

没有这样的事情。引用指向对象,而不是指向对象内的位置。期。这是Python对象模型的基本部分。

如果您愿意,可以写一个代表这样一个位置的课程:

class AttributeReference:
    def __init__(self, obj, attr):
        self.obj = obj
        self.attr = attr

    def set(self, value):
        setattr(self.obj, self.attr, value)

    # add get() and del() and other methods to your heart's content 


class ElementReference:
    def __init__(self, obj, key):
        self.obj = obj
        self.key = key

    def set(self, value):
        self.obj[self.key] = value

    # add get() and del() and other methods to your heart's content

然后你可以使用这样的对象而不是Python引用。 但是,使用起来相当笨重,因此使用它的标准要高得多。 从好的方面来说,嵌套的深度是完全无关紧要的。如果你想要一个"参考"到dictionary['k1']['k2']['k3']['k4'],这样做:ElementReference(dictionary['k1']['k2']['k3'], 'k4')

答案 2 :(得分:1)

您对指针有误解,特别是如何在Python中标记和访问变量。

从头开始,一个"指针"像C这样的低级语言只是一个包含内存地址的整数。通过特殊语法*pointer,您可以指示要访问内存位置的数据而不是表示位置的整数。你为什么要对整数进行操作?阅读指针算法,解释超出了这个答案的范围。

许多语言(包括Python)都假设您永远不需要直接对指针进行操作,因此,像您的变量名称pointer这样的Python变量名称具有与之关联的内存地址(我赢了&t; t进入堆栈vs堆这里,再次,超出范围),Python作为开发人员抽象远离你。在Python中,使用变量名称,您将始终直接访问数据。

在直接访问数据时,必须将该数据视为正确的类型。如果你不这样做,你会遇到像你看到的那样的错误。你可以"更新"指针,但这只是改变它指向的内存位置,而不是改变该位置的数据,因此不会反映在dictionary中。

为了解决一些困惑,请考虑Python中的变量名称为"标签" (文档使用我相信的这个术语)。 2个标签可能指向具有功能和属性的同一条数据,但标签本身不是具有功能和属性的对象。

其他人已经为您的列表与dict示例建议了具体的解决方案。我希望这能解释为什么"你所看到的。

答案 3 :(得分:1)

仍然不确定我是否完全理解你的问题,但这里有两种方法。假设你有这样的字典:

d = {'level1': {'level2': {'level3': {'level4': [1, 2, 3]}}}}

d['level1']['level2']['level3']['level4']为您提供最里面的列表的引用。如果你存储它,你可以用它做任何你想做的事情:

innerValue = d['level1']['level2']['level3']['level4']
innerValue.append(4)

>>> d
{'level1': {'level2': {'level3': {'level4': [1, 2, 3, 4]}}}}

正如其他人在评论中所指出的那样,你在这里修改的是列表。该列表不会“知道”#34;它在字典里面。您可以对该列表执行的操作与您可以对任何其他列表执行的操作相同。如果它不是一个列表而是一些其他类型的对象,同样适用:当它在dict中的内容与你在其他任何地方可以做的事情相同时你能做什么。如果要就地更新对象,则不会通知dict。因此,没有办法实现"通用"更新的方法是基于dict内部的对象这一事实,因为对象不知道他们是否在dicts内部。

另一种方法是存储对包含要修改的元素的dict的引用。然后你可以使用普通的dict操作来改变它的值:

innerDict = d['level1']['level2']['level3']
innerDict['level4'] = "Some other value"

>>> d
{'level1': {'level2': {'level3': {'level4': 'Some other value'}}}}

这种方法是普遍的"从某种意义上说它不依赖于那个内部字典中存储的值。在那里发生的是你正在更新内部字典,因此它的值指向一个新对象。但请注意,这会创建一个新对象,因此它不会就地修改原始列表(甚至可以在我的示例中更改它的值类型)。它确实修改了内部字典(通过为其中一个键指定一个新值)。

从你的问题中不清楚你想要实现什么,但是这两种方法可以在深层嵌套的dict中存储某种东西,然后混淆它。