循环修改Cube对象Face属性异常:双方面属性同步问题咨询
问题:Face对象属性更新后出现同步问题
我将「Cube」对象定义为包含6个「Face」对象(正方形)的列表(实现旋转功能前先只用2个),代码如下:
class Face(): def __init__(self, center, anglex = 0, angley = 0, color = (255,255,255),): self.center = center self.anglex = anglex self.angley = angley self.color = color def setAngle(self, anglex, angley): self.anglex = anglex self.angley = angley def setCenter(self, cx, cy): self.center[0] = cx self.center[1] = cy class Cube(): def __init__(self, center): self.center = center face1 = Face(center, 0, 0, (255,0,0)) face6 = Face(center, 180, 0, (0)) #self.faces = [face1, face2, face3, face4, face5, face6] self.faces = [face1, face6] height = 900 width = 1500 screen = pygame.display.set_mode([width, height]) cube = Cube([width/2, height/2])
当我尝试修改Face的中心和角度实现旋转效果时,属性无法正确更新,最终两个Face的角度/中心完全相同。
比如这段代码,循环内打印每个Face的center[0]时,结果是正确的:
for face in cube.faces: ax = (face.anglex + varx)%360 face.setAngle(ax, face.angley) cx = width/2 + math.sin(math.radians(face.anglex))*50 face.setCenter(cx, face.center[1]) print(face.center[0])
但如果把打印放到循环外,两个Face的center[0]就完全一样了:
for face in cube.faces: ax = (face.anglex + varx)%360 face.setAngle(ax, face.angley) cx = width/2 + math.sin(math.radians(face.anglex))*50 face.setCenter(cx, face.center[1]) for face in cube.faces: print(face.center[0])
我猜测是对类对象属性的工作机制理解有问题,求解释原因?
解答
核心问题是所有Face对象共享了同一个center列表引用。
列表是Python中的可变对象,当你在Cube的__init__方法里,把同一个center列表传给face1和face6时,这两个Face对象的self.center实际上指向内存中同一个列表。后续调用setCenter修改center[0]时,都是在修改这个共享的列表。
循环内打印看起来正确,是因为循环过程中:
- 第一次处理face1时,修改了共享列表的值,此时打印的是这个修改后的值
- 第二次处理face6时,又修改了同一个共享列表的值,打印的是这次修改后的结果
但循环结束后,两个Face的center属性依然指向同一个列表,所以最后一次修改的结果会覆盖之前的,导致两者的center完全相同。
修复方案
方案1:在Face类内部创建列表副本
修改Face的__init__方法,对传入的center创建副本,避免共享引用:
class Face(): def __init__(self, center, anglex = 0, angley = 0, color = (255,255,255),): self.center = center.copy() # 或者用 list(center) 创建副本 self.anglex = anglex self.angley = angley self.color = color
方案2:创建Face对象时传入副本
在Cube的__init__里,给每个Face传入center的副本:
face1 = Face(center.copy(), 0, 0, (255,0,0)) face6 = Face(center.copy(), 180, 0, (0))
两种方案都能让每个Face拥有独立的center列表,修改时就不会互相影响了。
内容的提问来源于stack exchange,提问作者marcoG
相关产品推荐
相关产品推荐

