所以我有一个名为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
然后我有一个继承自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
我创建了TrendingUser类的几个实例,并将它们存储在字典中,如下所示:
for user_id in user_ids:
dic[user_id] = TrendingUser(user_id)
现在,当我使用id()函数检查TrendingUser的各种实例的内存地址时,我得到不同的值。但是,当我检查每个TrendingUser实例的所有继承属性的内存地址时,除了comments属性(列表)之外,我在实例中获得相同的值。
一个附带问题:为什么会这样?
真正的问题是,当我编辑TrendingUser实例的一个继承属性时,例如更新bio,内存地址会发生变化,并且只更新了该实例的bio。 uploads属性不是这种情况,它是一个字典。当我将键值对插入我认为是单个TrendingUser实例的uploads属性时,它会将键值对添加到所有TrendingUser实例的uploads属性中。当我在插入键值对后检查uploads属性的内存地址是否发生了变化时,我意识到它没有,这解释了行为。
我想知道为什么这是字典的情况,而不是其他变量类型(我尝试过使用各种继承属性的类似练习),以及如何在从具有字典属性的Parent类继承时解决这个问题你想用吗?即我只想一次更新一个实例的继承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)
使用user_id = 11299389
更改TrendingUser的bio后(66809143, 4446746056, 4458480848, 4441785608, 140675510194976)
(60284557, 4446746056, 4458480560, 4441785608, 140675510194976)
(11299389, 4446746056, 4458667400, 4458804640*, 140675510194976)
使用user_id = 11299389向TrendingUser的uploads属性添加键值后
(66809143, 4446746056*, 4458480848, 4441785608, 140675510194976)
(60284557, 4446746056*, 4458480560, 4441785608, 140675510194976)
(11299389, 4446746056*, 4458667400, 4458804640, 140675510194976)
答案 0 :(得分:4)
在Python中,规则是“一旦创建,对象永远不会移动”。
该规则引用对象的头部(在调用id()时在CPython中看到的地址的部分)。在内部,可变容器指向数据的可变长度端口。如您所料,随着更多数据的添加,该数据的位置可以随处移动。
有关Python dicts如何工作的概述,请参阅我最近的PyCon talk和相关的slides。要更好地理解对象模型,请参阅Ned Batchelder's blog post。
关键是“python容器不包含任何东西”,它们只是对现有对象的引用。对于 TrendingUser ,底层实例字典指向相同的属性值(构建方法定义时创建的常量)。
在更新值时,对于TrendingUsers的实例,内存位置将指向您插入的新值,它们与默认值的地址不同(请记住,一旦创建,这些对象将永远不会移动)。
希望增加一点清晰度: - )
请参阅此Pytutor visualization了解您的代码所发生的事情。请注意,两个实例都引用相同的基础数据。
答案 1 :(得分:3)
默认参数uploads={}
是问题所在。它实际上是在类定义时创建dict并将该dict设置为默认值,而不是你想要的(如果没有指定则创建一个新的空字典)。为此,通常的模式是
def __init__(self, par=None):
if par is None:
par = {}