具有随机属性的Python对象列表

时间:2009-05-17 08:06:08

标签: python random

(编辑:randrange只是随机。范围,我没有写自己的RNG)

我正在尝试创建一个我定义的类的实例列表。这是整个班级(按要求):

from random import randrange

class Poly:
    points = [0] * 8
    fill = 'red'
    alpha = 1.0

    def __init__(self, width=100, height=100):
        for i in range(0, 8, 2):
            self.points[i] = randrange(width)
            self.points[i+1] = randrange(height)
        self.alpha = random()
        return

似乎工作正常:

>>> for i in range(5):
        Poly().points

[28, 64, 93, 26, 15, 31, 44, 50]
[24, 14, 47, 14, 35, 17, 63, 62]
[99, 28, 90, 29, 56, 59, 57, 33]
[62, 56, 48, 28, 40, 73, 70, 99]
[99, 32, 27, 99, 42, 57, 86, 12]

但是如果我尝试创建这些对象的列表,我会得到单独的实例(不同的内存地址),但它们都具有相同的随机值:

>>> p = []
>>> for i in range(5):
        p.append(Poly())

>>> p
[<gen_image.Poly instance at 0x02D773C8>, <gen_image.Poly instance at 0x02D77FD0>, <gen_image.Poly instance at 0x0321D030>, <gen_image.Poly instance at 0x02D51E40>, <gen_image.Poly instance at 0x02D51DA0>]

>>> for poly in p:
        print poly.points

[75, 18, 5, 76, 6, 64, 95, 54]
[75, 18, 5, 76, 6, 64, 95, 54]
[75, 18, 5, 76, 6, 64, 95, 54]
[75, 18, 5, 76, 6, 64, 95, 54]
[75, 18, 5, 76, 6, 64, 95, 54]

这里发生了什么?什么是我正在做的事情的正确方法?

4 个答案:

答案 0 :(得分:6)

将数组的创建移动到__init__方法。

您正在使用所有对象之间的共享数组。

第一个显示不同的原因是您在构造新的Poly对象之前打印该数组的内容,从而践踏数组内容。如果你把它们放在一边并稍后检查它们,那么它们看起来都与你生成的最后一个内容相同。

哦,在发布问题时尽量不要简化代码。始终发布完整但简短的程序来重现问题。

这是一个简短但完整的程序,用于演示您遇到的问题:

from random import randrange
class Poly:
    points = [0]*8

    def __init__(self, width=100, height=100):
        for i in range(0, 8, 2):
            self.points[i] = randrange(width)
            self.points[i+1] = randrange(height)
        return

p1 = Poly()
print "p1:", p1.points
p2 = Poly()
print "p2:", p2.points
print "p1:", p1.points

示例输出:

[C:\Temp] test.py
p1: [19, 5, 1, 46, 93, 18, 18, 57]
p2: [92, 71, 42, 84, 54, 29, 27, 71]
p1: [92, 71, 42, 84, 54, 29, 27, 71]

注意p1是如何变化的。

固定代码可以简单如下:

from random import randrange
class Poly:
    def __init__(self, width=100, height=100):
        self.points = [0]*8
        for i in range(0, 8, 2):
            self.points[i] = randrange(width)
            self.points[i+1] = randrange(height)
        return

虽然我更喜欢@Doug发布here

的附加变体

答案 1 :(得分:4)

您有一个类属性Poly.points。在__init__方法中,您执行self.points[i] = ...。现在这使得Python使用Poly.points,它由所有实例共享。但是您希望points成为实例属性。我建议这个:

class Poly:
    # you don't need this here
    #points = [0] * 8
    #fill = 'red'
    #alpha = 1.0

    def __init__(self, width=100, height=100):
        self.points = [0]*8
        self.fill = 'red'
        self.alpha = random()
        for i in range(0, 8, 2):
            self.points[i] = randrange(width)
            self.points[i+1] = randrange(height)

答案 2 :(得分:2)

积分列表全部被分享。看起来您将声明点作为实例或类的列表。如果您不想在实例之间共享列表,那么这不是在Python中执行操作的方式。尝试:


def __init__(self, width=100, height=100):
    self.points = [] #Create a new list
    for i in range(0, 8, 2):
        self.points.append(randrange(width))
        self.points.append(randrange(height))
    return

答案 3 :(得分:-1)

好的,这是罪魁祸首

points = [[0]] * 8

它分配相同的列表([0])8次而不是像

那样
points = []
for i in range(8):
    points.append([])