构造函数覆盖已创建对象的先前值

1 投票
1 回答
569 浏览
提问于 2025-04-18 01:04

我对Python还比较陌生。最近我在做一个项目,想创建两个对象:正方形(Square)和点(Points)。一个正方形是由四个点组成的,分别是左上角、右上角等等。

在我的主函数中,我创建了四个点对象,然后把它们传给正方形类的构造函数,这样就生成了我的正方形。

但是,当我用不同的点对象值再创建一个正方形时,之前创建的正方形的值被覆盖了,最后我得到的两个正方形是一样的。你知道这是为什么吗?

这是我的代码:

class Point(object):
    def __init__(self, x = 0, y = 0):
        self.x = x
        self.y = y

class Square(object):
    ul = Point()
    ll = Point()
    ur = Point()
    lr = Point()
    def __init__(self, ul, ll, ur, lr):
        self.ul.x = ul.x
        self.ll.x = ll.x
        self.ur.x = ur.x
        self.lr.x = lr.x
        self.ul.y = ul.y
        self.ll.y = ll.y
        self.ur.y = ur.y
        self.lr.y = lr.y

def main():
    ul1 = Point(1, 2)
    ll1 = Point(1, 1)
    ur1 = Point(2, 2)
    lr1 = Point(2, 1)
    s1 = Square(ul1, ll1, ur1, lr1)

    ul2 = Point(3, 3)
    ll2 = Point(3, 2)
    ur2 = Point(4, 3)
    lr2 = Point(4, 2)
    s2 = Square(ul2, ll2, ur2, lr2)

    #At this point s1 and s2 have the same values...

if __name__ == '__main__':
    main()

任何帮助我都会非常感激;)

谢谢!

1 个回答

5

这个问题发生的原因是你在 Square 类中把四个角的变量定义成了类变量。这意味着这些变量在这个类的所有实例之间是共享的。

下面是你 Square 类的一个更清晰的版本。这里使用了实例变量 self.ul, self.ll 等等。你在 __init__ 方法中不需要为这些指定一个 Point 实例,因为你已经在主函数中把它们作为参数传入了。

class Square(object):
    def __init__(self, ul, ll, ur, lr):
        self.ul = ul
        self.ll = ll
        self.ur = ur
        self.lr = lr 

def main():
    s1 = Square(Point(1, 2), Point(1, 1), Point(2, 2), Point(2, 1))
    s2 = Square(Point(3, 3), Point(3, 2), Point(4, 3), Point(4, 2))
    print s1.ul.x # 1
    print s1.lr.y # 2

HyperBoreus 提到的一个好点子是把点作为参数传递。如果你把同一个点对象传给两个正方形并修改它,那么你所做的任何更改都会在两个正方形中反映出来。

你可以通过把角的值传给 __init__ 方法,而不是 Point 对象,来解决这个问题,然后在 __init__ 方法中创建实例。

下面是一个完整的例子:

class Point(object):
    def __init__(self, x = 0, y = 0):
        self.x = x
        self.y = y

class Square(object):
    def __init__(self, ul, ll, ur, lr):
        self.ul = Point(ul[0], ul[1])
        self.ll = Point(ll[0], ll[1])
        self.ur = Point(ur[0], ur[1])
        self.lr = Point(lr[0], lr[1])

def main():
    square_one = Square((1, 2), (1, 1), (2, 2), (2, 1))
    square_two = Square((3, 3), (3, 2), (4, 3), (4, 2))

我还建议你使用更易读的变量名。把 upper_right 简化成 ur 并没有什么好处。相反,当你一年后再回来看这段代码时,你会对自己感到很懊恼。

撰写回答