在循环 Python 中创建对象——令人费解的行为
Creating objects in a loop Python -- puzzling behavior
我查看了看起来相似但实际上不同的问题 (here, here and here) 的解决方案。我仍然无法理解这里发生的事情。
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
变量并看到当最外层循环处于第二次迭代时它已经被填充。但是怎么办?我不应该得到一个新的空对象吗?
我不是在寻找解决问题或获得预期输出的方法,我知道一些方法。我想了解为什么会得到这个输出。
谢谢!
def __init__(self, l = []):
有点创建 l
的全局默认值,稍后可以更改(page.lines
引用此全局数组,它不会在每次调用时重新创建)。
稍微好一点的实现:
class Page:
def __init__(self, l = None):
self.lines = l if l else []
我可以推荐类似下面的内容吗?
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()
的问题是您的 Page
class 的初始化程序在它创建的所有实例之间共享列表。解决此问题的一种方法是要求 class 的调用者始终传入一个用于存储页面的列表。否则,您可以执行类似于上面代码中所示的操作。
我查看了看起来相似但实际上不同的问题 (here, here and here) 的解决方案。我仍然无法理解这里发生的事情。
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
变量并看到当最外层循环处于第二次迭代时它已经被填充。但是怎么办?我不应该得到一个新的空对象吗?
我不是在寻找解决问题或获得预期输出的方法,我知道一些方法。我想了解为什么会得到这个输出。
谢谢!
def __init__(self, l = []):
有点创建 l
的全局默认值,稍后可以更改(page.lines
引用此全局数组,它不会在每次调用时重新创建)。
稍微好一点的实现:
class Page:
def __init__(self, l = None):
self.lines = l if l else []
我可以推荐类似下面的内容吗?
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()
Page
class 的初始化程序在它创建的所有实例之间共享列表。解决此问题的一种方法是要求 class 的调用者始终传入一个用于存储页面的列表。否则,您可以执行类似于上面代码中所示的操作。