Python список объектов со случайными атрибутами - PullRequest
1 голос
/ 17 мая 2009

(Правка: 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 ]

6 голосов
/ 17 мая 2009

Переместить создание массива в метод __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 опубликовал здесь

4 голосов
/ 17 мая 2009

У вас есть атрибут класса 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 голосов
/ 17 мая 2009

Списки баллов являются общими. Может показаться, что вы объявляете точки списком экземпляра или класса. Это не способ делать вещи в 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

0 голосов
/ 17 мая 2009

хорошо, вот виновник

баллов = [[0]] * 8

он присваивает один и тот же список ([0]) 8 раз, вместо этого вы должны сделать что-то вроде

points = []
for i in range(8):
    points.append([])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...