美文网首页python热爱者Python新世界
今天长见识了,有人说python有个BUG,我去试了下居然是真的

今天长见识了,有人说python有个BUG,我去试了下居然是真的

作者: 48e0a32026ae | 来源:发表于2018-11-22 19:27 被阅读4次

    今天在像以前一样 做题的时候,遇到一个迷一样的 BUG ,仔细一想才想起来这是Python的一个特性,以前也遇到过,没想到今天又遇到了。话不多说,先来看题:

    学习Python中有不明白推荐加入交流群

                    号:516107834

                    群里有志同道合的小伙伴,互帮互助,

                    群里有不错的学习教程!

    题目要求

    问题描述

    在一个定义了直角坐标系的纸上,画一个(x1,y1)到(x2,y2)的矩形指将横坐标范围从x1到x2,纵坐标范围从y1到y2之间的区域涂上颜色。

    下图给出了一个画了两个矩形的例子。第一个矩形是(1,1) 到(4, 4),用绿色和紫色表示。第二个矩形是(2, 3)到(6, 5),用蓝色和紫色表示。图中,一共有15个单位的面积被涂上颜色,其中紫色部分被涂了两次,但在计算面积时只计算一次。在实际的涂色过程中,所有的矩形都涂成统一的颜色,图中显示不同颜色仅为说明方便。

    给出所有要画的矩形,请问总共有多少个单位的面积被涂上颜色。

    输入格式

    输入的第一行包含一个整数n,表示要画的矩形的个数。

    接下来n行,每行4个非负整数,分别表示要画的矩形的左下角的横坐标与纵坐标,以及右上角的横坐标与纵坐标。

    输出格式

    输出一个整数,表示有多少个单位的面积被涂上颜色。

    样例输入

    2

    1 1 4 4

    2 3 6 5

    样例输出

    15

    评测用例规模与约定

    1<=n<=100,0<=横坐标、纵坐标<=100。

    当时我的答案是这样的:

    n = int(input())

    # 生成一个坐标系块,默认全为 0

    panel = [[0]*100]*100

    # 色块数量

    cnt = 0

    for i in range(n):

    read = [int(x) for x in input().split()]

    for x in range(read[0], read[2]):

    for y in range(read[1], read[3]):

    if panel[x][y] == 0:

    panel[x][y] = 1

    cnt += 1

    print(cnt)

    却发现结果不太对,输入示例数据,结果只有 4 ?剩下的 11 个是被吃了吗?仔细看逻辑也没问题啊,这时候突然想到 Python 的一个特性,赶紧写个测试代码试一下:

    a = [[0]*3]*3

    print(a)

    a[0][0] = 1

    print(a)

    结果如下:

    [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

    [[1, 0, 0], [1, 0, 0], [1, 0, 0]]

    我们发现,明明只是置 [0][0] 为 1 ,怎么所有的第二维数组的 [0] 全为 1 了呢?你遇到过这种情况吗?

    原来这是因为 Python 相同的值只存一份的特性决定的。不管有多少个 [0,0,0] 对于 Python 来说,内存中只存一份,所有的 [0,0,0] 都是这块内存的引用,所以在对二维数组的 [0][0] 进行赋值的时候,内存中的值被改变,所有 [0,0,0] 的引用也被改变!正是这个原因,所有答案输出的结果才与我们预期的不一样。要想正确输出只需将代码稍微改一下即可:

    n = int(input())

    panel = [0]*10000

    cnt = 0

    for i in range(n):

    read = [int(x) for x in input().split()]

    for x in range(read[0], read[2]):

    for y in range(read[1], read[3]):

    if panel[x*100+y] == 0:

    panel[x*100+y] = 1

    cnt += 1

    print(cnt)

    其实对于 Python 来说,不光是相同的列表只存一份,元组、集合、字典也是只存一份,所以一个相同的数据赋值给多个变量时,如果进行修改操作时要小心了,一不小心就把所有的地方都改了。

    另外对于 ‘a' , 1 等常量也遵循只存一份的原则。

    a = 1

    b = 1

    对于以上代码,将 1 赋值给 a ,再将 1 赋值给 b 。在这里 a 代表的 1 和 b 代表的 1 其实是同一个 1 ,引用的是同一个地址。也就是说,在 Python 中,没有真正的值传递,所有的数据都是引用类型的。只不过指向常量等不可变类型的变量在改变时会换一个内存地址,若是列表这种可变类型,在修改时就会直接修改内存中的值,因此所有的引用都会被改变。你明白了吗?

    相关文章

      网友评论

        本文标题:今天长见识了,有人说python有个BUG,我去试了下居然是真的

        本文链接:https://www.haomeiwen.com/subject/rdrrqqtx.html