【问题标题】:Object appended to a list instance appears in a different instance of that list附加到列表实例的对象出现在该列表的不同实例中
【发布时间】:2010-12-24 01:29:27
【问题描述】:

我正在编写这段小代码作为面向对象编程的练习。

在这里,我试图将房屋定义为房间列表,并将每个房间定义为设备列表(例如灯)。

首先,我创建了所有对象,它们将两个房间附加到房子上,并将不同的设备附加到每个房间。很基本。

问题是设备似乎被附加到两个房间。这是为什么呢?

代码:

#! /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 中。

【问题讨论】:

标签: python default mutable arguments


【解决方案1】:

默认参数在方法声明时被评估一次。然后在对该方法的所有调用中使用该值。

关于stackoverflow exploring the reasons for this design 以及如何best avoid these mutable default arguments 的其他问题。

【讨论】:

    【解决方案2】:
    def __init__(self, name = 'a room', devs = list()):
        self.name = name
        self.devs = devs
        print('room ' + self.name + ' created')
    

    当您这样做时,list() 实际上总是相同的列表。每次调用构造函数时,您都不会得到 new 空列表,而是得到 same 空列表。要解决这个问题,您需要制作一个副本。

    另外,list() 更习惯地写成[]

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

    【讨论】:

      【解决方案3】:

      函数的默认参数值只计算一次。这意味着 House 的所有实例将使用 self.rooms 的相同列表实例(如果在构造中未给出房间参数)。以同样的方式,所有 Room 实例都将共享相同的 self.devs 列表。

      要解决这个问题,请编写如下代码:

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

      其他类也是如此。

      【讨论】:

      • +1:黄金法则:永远不要使用可变对象作为默认值。
      猜你喜欢
      • 2012-06-19
      • 2019-08-15
      • 1970-01-01
      • 1970-01-01
      • 2020-05-27
      • 1970-01-01
      • 2017-07-06
      • 2013-10-08
      • 2020-03-12
      相关资源
      最近更新 更多