Объект, добавленный к экземпляру списка, появляется в другом экземпляре этого списка - PullRequest
1 голос
/ 07 декабря 2009

Я писал этот маленький кусочек кода в качестве упражнения в объектно-ориентированном программировании.

Здесь я пытаюсь определить дом как список комнат, а каждую комнату - как список устройств (например, ламп).

Сначала я создал все объекты, и они добавили две комнаты к дому и разные устройства к каждой комнате. Довольно простой.

Проблема в том, что кажется, что устройство добавляется в обе комнаты. Почему это так?

Код:

#! /usr/bin/python

class House:
        def __init__(self, rooms = list()):
                self.rooms = rooms
                print('house created')


class Room:
        def __init__(self, name = 'a room', devs = list()):
            self.name = name
            self.devs = devs
            print('room ' + self.name + ' created')


class Device:
        def __init__(self, name = 'a device'):
                self.name = name
                print('device ' + self.name + ' created')


def main():
        #1
        h = House()
        r1 = Room(name = 'R1')
        r2 = Room(name = 'R2')
        d1 = Device(name = 'lamp1')
        d2 = Device(name = 'lamp2')

        #2
        h.rooms.append(r1)
        h.rooms.append(r2)

        for room in  h.rooms:
                print room.name

        print h.rooms[0]
        print h.rooms[1]
        h.rooms[1].devs.append(d1)

        #3
        for room in h.rooms:
                print room.name
                for dev in room.devs:
                        print('room ' + room.name + ' > ' + dev.name)
                        print room
                        print dev


if __name__ == '__main__' : main()

И вывод.

house created
room R1 created
room R2 created
device lamp1 created
device lamp2 created
R1
R2
<__main__.Room instance at 0xb7d8a58c>
<__main__.Room instance at 0xb7d8a5ac>
R1
room R1 > lamp1
<__main__.Room instance at 0xb7d8a58c>
<__main__.Device instance at 0xb7d8a5cc>
R2
room R2 > lamp1
<__main__.Room instance at 0xb7d8a5ac>
<__main__.Device instance at 0xb7d8a5cc>

Обратите внимание, что один и тот же экземпляр d1 находится в обеих комнатах, r1 и r2.

Ответы [ 3 ]

9 голосов
/ 07 декабря 2009

Значения параметров по умолчанию для функций оцениваются только один раз. Это означает, что все экземпляры House будут использовать один и тот же экземпляр списка для self.rooms (если параметр rooms не был задан в конструкции). Таким же образом все экземпляры Room будут использовать один и тот же список для self.devs.

Чтобы решить эту проблему, напишите код так:

def __init__(self, rooms = None):
    if rooms is None:
        rooms = []
    self.rooms = rooms
    print('house created')

И то же самое для других классов.

3 голосов
/ 07 декабря 2009

Аргумент по умолчанию оценивается один раз, в точке объявления метода. Это значение затем используется во всех вызовах метода.

Есть еще один вопрос о стеке потока , исследующем причины такого дизайна и как лучше всего избегать этих изменяемых аргументов по умолчанию .

0 голосов
/ 07 декабря 2009
def __init__(self, name = 'a room', devs = list()):
    self.name = name
    self.devs = devs
    print('room ' + self.name + ' created')

Когда вы делаете это list() на самом деле всегда один и тот же список. Вы не получаете новый пустой список каждый раз, когда вызывается конструктор, вы получаете такой же пустой список. Чтобы исправить это, вы захотите сделать копию.

Также list() более идиоматически записывается как [].

def __init__(self, name='a room', devs=[]):
    self.name = name
    self.devs = list(devs)
    print('room ' + self.name + ' created')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...