美文网首页
【Note】搬砖路上遇到的坑

【Note】搬砖路上遇到的坑

作者: 火禾子_ | 来源:发表于2019-03-10 11:41 被阅读0次

    1 关于内存管理的那些事(is VS ==)

    首先,变量类型分为一下两个大类。

    可变类型,值可以改变:

    • 列表 list
    • 字典 dict

    不可变类型,值不可以改变:

    • 数值类型 int, long, float
    • 布尔类型 bool
    • 字符串 str
    • 元组 tuple

    1-1 怎么体现是可变/不可变的类型呢?

    背景:在python中通过 = 复制的变量,都是同时即把变量的值,也把变量在内存中的地址复制也过去了(这样的说法不是绝对正确的,在命令行中不是通用的)。即 = 复制过的变量不仅内存地址一样,变量的值也一样。但是需要注意的是:对于不可变类型(如 int)的变量,如果要更改变量的值,则会创建一个新值,并且给这个新值分配一个新的内存地址,然后把变量指向这个新值的内存地址上,而旧值如果没有被引用就等待垃圾回收。如果是可变类型变量,若修改变量的值,则可以直接修改变量的值,变量的引用地址不会变。

    不可变类型 注意 python 中创建两个内容一样的变量时(变量名不一样),一般都会在内存中分配两个内存地址分别给这两个变量。即两个变量的内容虽然一样,但是变量的引用地址不一样。所以两个变量使用 == 比较成立,但是使用 is 比较不成立。这里有两个特例,小整数和 str,稍后会详细介绍。

    以 int 类型为例,当创建完对象后,内存就不可变。所以当要改变值的时候,只能另辟一块内存来存储新计算出来的值。而之前开辟的内存里存储的值不变。

    下面代码中 b 的值和地址都没变,也没有随着 a 的值改变而改变,就是这个道理。b 仍指向原来的内存,而 a 指向新的内存。

    a = 10
    b = a
    print(a, id(a), b, id(b))
    a += 2
    print(a, id(a), b, id(b))
    
    输出:
    10 4310353248 10 4310353248
    12 4310353312 10 4310353248
    

    可变类型 以列表为代表,内存是可扩充的。因此,当 list1 改变时,是在本来的内存上扩充的,list1 和 list2 仍指向原来的内存。

    list1 = ['a']
    list2 = list1
    print(list1, id(list1), list2, id(list2))
    list1.append('b')
    print(list1, id(list1), list2, id(list2))
    
    输出:
    ['a'] 4342566728 ['a'] 4342566728
    ['a', 'b'] 4342566728 ['a', 'b'] 4342566728
    

    1-2 体现在 is 和 == 上,是什么情况呢?

    • == 判断 内容/值是否相同
    • is 判断内容/值是否相同 && 内存地址是否相同

    所以相应的,对于可变类型,因为赋值时给的是引用,内存大小可以随着值的变化而自动扩容,所以无论是 == 还是 is 都是 True。对于不可变类型,在 PyCharm 中,只要是 == 判定为 True 的,一般 is 也会判定为 True。为什么有个 PyCharm 的前提呢?那就接着往下看吧。

    1-3 特例一:使用 is 时注意 python 对于小整数使用对象池存储问题

    注意,因为 python 对小整数在内存中直接创建了一份,不会回收。因此所有创建的小整数变量直接从对象池中引用即可。
    但是注意 python 仅仅对比较小的整数对象进行缓存(范围 [-5, 256] )缓存起来,而并非是所有整数对象。也就说只有在这个 [-5,256] 范围内创建的变量值使用 is比较时候才会成立。

    >>> a = 10
    >>> b = 10
    >>> c is d
    True
    >>> c = 1000
    >>> d = 1000
    >>> c is d
    False
    >>> e ,d ,f ,g = -5 ,-5 ,-6 ,-6
    >>> e is d
    True
    >>> f is g  #超过-5的范围不成立
    False
    

    注意:上面对于 python 小整数对象池的使用仅仅是在命令行中执行可以,而在 Pycharm/保存为文件 执行,结果是不一样的,这是因为解释器做了一部分优化。即在使用pycharm时,即使整数超过 256,使用 is 也是成立的。

    1-4 特例二:使用 is 时注意 python 关于字符串的 intern 机制存储

    python 中虽然字符串对象也是不可变对象,但 python 有个 intern 机制,简单说就是维护一个字典,这个字典维护已经创建字符 (key) 和它的字符串对象的地址 (value),每次创建字符串对象都会和这个字典比较,没有就创建,重复了就用指针进行引用就可以了。相当于 python 对于字符串也是采用了对象池原理。

    但是注意:如果字符串(含有空格),不可修改,没开启intern机制,不共用对象。比如"a b"和"a b"。

    同样地,这种情况使用 is 不成立的形式只有在命令行中可以。使用pycharm 同样是 True,因为做了优化。

    >>> s1, s2 = 'abc', 'abc'
    >>> s1 is s2
    True
    >>> s1, s2 = 'a b', 'a b'
    >>> s1 is s2
    False
    

    PS. 本小节参考了 Python中is与==的使用区别详解

    2 matplotilb.pyplot 与 pylab 的联系与区别

    根据 pyplot 源码 pyplot.py 中的解释部分就可得知:

    matplotlib.pylab combines pyplot with numpy into a single namespace. 
    This is convenient for interactive work, but for programming it is recommended that the namespaces be kept separate.
    

    意思就是说 pylab 结合了 pyplot 和 numpy,对交互式使用来说比较方便,既可以画图又可以进行简单的计算。但是,对于一个项目来说,建议分别倒入使用,即:

    import numpy as np
    import matplotlib.pyplot as plt
    

    而不是

    import pylab as pl
    

    附在使用matplotlib及相关模块时可能用得上的资料网址:

    相关文章

      网友评论

          本文标题:【Note】搬砖路上遇到的坑

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