2

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

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'  

我知道 list 没有更新功能,并且知道我可以执行以下操作:

pointer[0] = 2

...但我想要一个更通用的选项来更新参考值,所以对象仍然属于字典,但值已经改变。

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

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

我的问题不是针对 list 是否具有更新功能-而是我在问是否有更简洁的方法来引用和更改深度嵌套字典中的值,因此将其存储在参考值中会更好看而不是每次我想分配一些东西时都输入它。

谢谢!

编辑:第一个示例中的固定语法
EDIT2:让我明确一点:我知道列表没有update功能,而是我在询问通用参考值更新
EDIT3:简化问题

4

4 回答 4

5

哪有这回事。引用指向对象,而不是对象内部的位置。时期。这是 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')

于 2014-09-17T21:10:36.917 回答
3

从错误消息中可以明显看出, alist没有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']
于 2014-09-17T21:02:08.977 回答
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]}}}}

但是,正如其他人在评论中指出的那样,您在此处修改的是list。该列表不“知道”它在字典中。您可以对该列表执行的操作与您可以对任何其他列表执行的操作相同。如果它不是列表而是其他类型的对象,则同样适用:当它位于 dict 中时,您可以对它执行的操作与您在其他任何地方可以对它执行的操作相同。如果您想就地更新对象,则不会通知 dict。所以没有办法有一个“通用”的更新方法,它基于对象在字典中的事实,因为对象不知道它们是否在字典中。

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

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

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

这种方法是“通用的”,因为它不依赖于该内部字典中存储的值类型。那里发生的事情是您正在更新该内部字典,因此它的值指向一个新对象。但是请注意,这会创建一个新对象,因此它不会就地修改原始列表(甚至可以在我的示例中更改它的值类型)。它确实就地修改了内部字典(通过为其一个键分配一个新值)。

从您的问题中不清楚您要达到什么目的,但这是两种方法来存储某种对深度嵌套的字典中的某些内容的引用,然后将其弄乱。

于 2014-09-17T21:22:30.810 回答
1

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

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

包括 Python 在内的许多语言都假定您永远不需要直接对指针进行操作,因此虽然像您的变量这样的 Python 变量名pointer具有与之关联的内存地址(我不会再在这里讨论堆栈与堆)范围),Python 将其抽象为开发人员。在 Python 中,使用变量名,您将始终直接访问数据。

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

为了消除一些混淆,将 Python 中的变量名视为“标签”(我相信文档使用这个术语)。2个标签可能指向同一条具有功能和属性的数据,但标签本身并不是具有功能和属性的对象。

其他人已经为您的 list vs dict 示例提出了具体的解决方案。我希望这能解释你所看到的“为什么”。

于 2014-09-17T21:19:41.890 回答