Python 3.2中类的所有实例共享同一个字典属性

0 投票
1 回答
1082 浏览
提问于 2025-04-17 19:35

我正在用Python写一个太空贸易游戏,我决定把地图分成更小的块,这样可以减少每次在屏幕上绘制时需要考虑的对象数量。

这个问题是通过一个叫做Sector的对象来解决的,Sector的定义如下:

class Sector:
   x=0     #Position of the sector. The galactic (absolute) position of any object is its in-sector position
   y=0     #plus the galactic position offset times the size of a sector. 
   stardict=dict()

然后,生成器代码会给每个区域(目前有100个)填充75颗星星,这些星星保存在一个叫做stardict的字典里。

thesector=Sector()

size=size/2

#Generate stars
for t in range(stars):
    #name="Star "+str(t)
    name=generate_name().capitalize()
    thesector.stardict[name]=Star( name, (random.randint(-size,size), random.randint(-size,size)), (random.randint(0,255), random.randint(0,255), random.randint(0,255)), random.randint(3,7))

    if math.floor((t/stars)*100)==(t/stars)*100: print("Generating stars: "+str((t/stars)*100)+"% done.")

不过,当我尝试运行程序时,遇到了一些奇怪的错误,打开调试器后发现原因:每个区域的stardict属性都是一样的,它们里面包含的星星完全相同(不是重复的,它们的内存地址也一样)。根据我的观察,每个Sector.stardict实际上都在引用同一个字典对象。

我不知道为什么会这样。有没有人能帮我解释一下?

1 个回答

5

他们指的是同一个对象。这是一个非常常见的误区。如果你想让它们各自拥有自己的 dict,你需要在 __init__ 方法中创建它。

class Sector:
   x = 0     #Position of the sector. The galactic (absolute) position of any object is its in-sector position
   y = 0     #plus the galactic position offset times the size of a sector. 
   def __init__(self):
       self.stardict = dict()

根据你现在的代码,当你通过 self.stardict 访问 stardict 时,Python 首先会在这个对象的实例中查找 stardict,如果找不到,就会去类里面查找。它在类中找到了 stardict,所以就使用这个了。但是,这意味着所有的实例都找到了同一个 stardict(因为它们都是同一个类的实例)——如果其中一个实例更新了它的 stardict,其他的实例也会立刻知道(比光速还快!)*

*注意,这并不违反任何物理定律。因为它们是同一个对象,所以信息没有距离可言……

撰写回答