Python:为什么添加键值对后继承的字典属性的内存位置不会改变

use*_*894 0 python inheritance dictionary memory-address python-2.7

所以我有一个名为 User_1 的父类,User_1 的 init 方法如下所示:

class User_1(object):
    def __init__(self, user_id, bio="", likes=0, uploads={}, follows=0, dateJoined=None, accountType=""):
        self.user_id = user_id
        self.bio = bio
        self.likes = likes
        self.uploads = uploads
        self.follows = follows
        self.dateJoined = dateJoined
        self.accountType = accountType
        self.comments = []
        self.responseCommentsCount = 0
Run Code Online (Sandbox Code Playgroud)

然后,我有一个继承自 User_1 类的类,称为 TrendingUsers,它的 init 方法如下所示:

class TrendingUser(User_1):
    def __init__(self, user_id):
        User_1.__init__(self, user_id)

        self.averageTSWords = 0.0
        self.averageSSWords = 0.0
        self.percOfClipTitlesUntitled = 0.0
        self.percOfClipsWithCaptions = 0.0
        self.percOfClipsWithTags = 0.0
        self.percOfClipsWithComments = 0.0
        self.percOfPurgatoryClips = 0.0
        self.averageTimeDifferenceBetweenUploaded = 0.0
Run Code Online (Sandbox Code Playgroud)

我创建了 TrendingUser 类的几个实例,并将它们存储在字典中,如下所示:

for user_id in user_ids:
    dic[user_id] = TrendingUser(user_id)
Run Code Online (Sandbox Code Playgroud)

现在,当我使用 id() 函数检查 TrendingUser 的各个实例的内存地址时,我得到了不同的值。但是,当我检查每个 TrendingUser 实例的所有继承属性的内存地址时,我在实例中获得相同的值,除了注释属性(列表)之外。

附带问题:为什么会出现这种情况?

真正的问题是,当我编辑 TrendingUser 实例的继承属性之一(例如更新简介)时,内存地址会发生变化,并且只有该实例的简介被更新。uploads 属性的情况并非如此,它是一个字典。当我将键值对插入到我认为是单个 TrendingUser 实例的上传属性中时,它会将键值对添加到所有 TrendingUser 实例的上传属性中。当我检查插入键值对后 uploads 属性的内存地址是否发生变化时,我意识到它没有变化,这解释了这种行为。

我想知道为什么字典会出现这种情况,而不是其他变量类型(我已经尝试过使用各种继承属性进行类似的练习),以及当从具有您想要的字典属性的父类继承时如何解决这个问题使用?即我只想一次更新一个实例的继承上传属性,而不是一次更新所有实例。

任何有关此事的帮助将不胜感激。谢谢。

编辑:

这可能有帮助:

在做任何事情之前:

('user_id', 'memory_address_uploads_attribute', 'memory_address_comments_attribute', 'memory_address_bio_attribute', 'memory_address_follows_attribute')
(66809143, 4446746056, 4458480848, 4441785608, 140675510194976)
(60284557, 4446746056, 4458480560, 4441785608, 140675510194976)
(11299389, 4446746056, 4458667400, 4441785608, 140675510194976)
Run Code Online (Sandbox Code Playgroud)

将 TrendingUser 的个人简介更改为 user_id = 11299389 后

(66809143, 4446746056, 4458480848, 4441785608, 140675510194976)
(60284557, 4446746056, 4458480560, 4441785608, 140675510194976)
(11299389, 4446746056, 4458667400, 4458804640*, 140675510194976)
Run Code Online (Sandbox Code Playgroud)
  • 内存地址改变了

在 user_id = 11299389 的 TrendingUser 的 uploads 属性中添加键值后

(66809143, 4446746056*, 4458480848, 4441785608, 140675510194976)
(60284557, 4446746056*, 4458480560, 4441785608, 140675510194976)
(11299389, 4446746056*, 4458667400, 4458804640, 140675510194976)
Run Code Online (Sandbox Code Playgroud)
  • 没有变化,现在这三个 TrendingUser 实例的所有上传属性都有插入的键值对

Ray*_*ger 5

在Python中,规则是“对象一旦创建,就永远不会移动”。

该规则引用对象的头部(您在 CPython 中调用id()时看到的地址部分)。在内部,可变容器指向数据的可变长度端口。正如您所怀疑的,随着更多数据的添加,该数据的位置可能会移动。

有关 Python 字典如何工作的概述,请参阅我最近的PyCon 演讲和相关幻灯片。为了更好地理解对象模型,请参阅Ned Batchelder 的博客文章

关键点是“Python 容器不包含任何内容”,它们只包含对现有对象的引用。对于TrendingUser,底层实例字典指向相同的属性值(构建方法定义时创建的常量)。

当您更新值时,对于 TrendingUsers 的实例,内存位置将指向您插入的新值,并且它们不会是与默认值相同的地址(请记住,一旦创建,这些对象将永远不会移动)。

希望这能增加一点清晰度:-)

请参阅此Pytutor 可视化,了解您的代码所发生的情况。请注意,两个实例都引用相同的基础数据。