【问题标题】:Creating objects in a loop Python -- puzzling behavior在循环 Python 中创建对象——令人费解的行为
【发布时间】:2020-10-06 12:21:30
【问题描述】:

我查看了看起来相似但实际上并非如此的问题的解决方案(hereherehere)。我仍然无法理解这里发生了什么。

class Page:
    def __init__(self, l = []):
        self.lines = l

    def __repr__(self):
        return str(self.lines)

class Line:
    def __init__(self, string=None):
        self.str = string

    def __repr__(self):
        return str(self.str)


if __name__ == '__main__':
    data = [[1, 2, 3], [4, 5, 6]]
    pages = []
    for row in data:
        page = Page()
        #print(page)
        #print(id(page))
        for x in row:
            line = Line(str(x))
            page.lines.append(line)
        pages.append(page)
print('Pages: ', pages)

我期待的答案是

Pages: [1, 2, 3], [4, 5, 6]

我得到的是

Pages: [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]]

我打印了page 变量,当最外层循环在第二次迭代中时,它已经被填充了。但是怎么做?我不应该得到一个新的空对象吗?

我不是在寻找解决问题的方法或获得预期的输出,我知道一些方法。我想了解为什么会得到这个输出。

谢谢!

【问题讨论】:

    标签: python-3.x loops oop garbage-collection


    【解决方案1】:

    def __init__(self, l = []): 有点创建l 的全局默认值,您稍后更改(page.lines 指的是这个全局数组,它不会在每次调用时重新创建)。

    稍微好一点的实现:

    class Page:
        def __init__(self, l = None):
            self.lines = l if l else []
    

    【讨论】:

    • 啊!所以self.lines 只是简单地存储对全局列表l 的引用,并创建一个 Page 对象每次都会更改这个全局列表。
    【解决方案2】:

    我可以建议以下内容吗?

    def main():
        data = [[1, 2, 3], [4, 5, 6]]
        pages = []
        for row in data:
            page = Page()
            print(page)
            print(id(page))
            for x in row:
                line = Line(str(x))
                page.append(line)
            pages.append(page)
        print('Pages:', pages)
    
    
    class Page:
        def __init__(self, lines=None):
            if lines is None:
                lines = []
            if not isinstance(lines, list):
                raise TypeError('argument must by of type list')
            if not all(isinstance(item, Line) for item in lines):
                raise TypeError('list must only contain items of type Line')
            self.__lines = lines
    
        def __repr__(self):
            return f'{type(self).__name__!s}({self.__lines!r})'
    
        def append(self, line):
            if not isinstance(line, Line):
                raise TypeError('argument must be of type Line')
            self.__lines.append(line)
    
    
    class Line:
        def __init__(self, text=None):
            if text is None:
                text = ''
            if not isinstance(text, str):
                raise TypeError('argument must be of type str')
            self.__text = text
    
        def __repr__(self):
            return f'{type(self).__name__!s}({self.__text!r})'
    
    
    if __name__ == '__main__':
        main()
    

    Green_Wizard points out 的问题在于,Page 类的初始化程序在它创建的所有实例之间共享列表。您可以解决此问题的一种方法是要求类的调用者始终传入一个列表来存储您的页面。否则,您可以执行类似于上面代码中显示的操作。

    【讨论】:

      猜你喜欢
      • 2018-01-16
      • 1970-01-01
      • 1970-01-01
      • 2014-06-28
      • 1970-01-01
      • 2020-10-30
      • 2016-11-18
      • 2018-07-02
      • 2020-06-19
      相关资源
      最近更新 更多