• 生成器和迭代器,深浅拷贝


    一、迭代器

    对于Python 列表的 for 循环,他的内部原理:查看下一个元素是否存在,如果存在,则取出,如果不存在,则报异常 StopIteration。(python内部对异常已处理)

    class listiterator(object)
     |  Methods defined here:
     |  
     |  __getattribute__(...)
     |      x.__getattribute__('name') <==> x.name
     |  
     |  __iter__(...)
     |      x.__iter__() <==> iter(x)
     |  
     |  __length_hint__(...)
     |      Private method returning an estimate of len(list(it)).
     |  
     |  next(...)
     |      x.next() -> the next value, or raise StopIteration
    
    listiterator

    二、生成器

    通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

    所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。

    要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator,或者生成器内部基于yield创建,即:对于生成器只有使用时才创建,从而不避免内存浪费

    所以,我们创建了一个generator后,基本上永远不会调用next()方法,而是通过for循环来迭代它。

    generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

    比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

    1, 1, 2, 3, 5, 8, 13, 21, 34, ...

    三,深浅拷贝

    当进行修改时,想要保留原来的数据和修改后的数据,而在python中深浅拷贝是不一样的,特别是在数字字符串和集合在修改时差异:

    在修改数据时:对于数字字符串,在内存中重新新建一份数据,集合则是修改内存中的同一份数据

    对于list,tuple,dict,set中的元素,若想要进行拷贝以后的修改的话最好进行深拷贝比较不容易出错,否则还是很容易出错的。

    Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果

    其实这个是由于共享内存导致的结果

    拷贝:原则上就是把数据分离出来,复制其数据,并以后修改互不影响。

    先看 一个非拷贝的例子

    =赋值:数据完全共享(=赋值是在内存中指向同一个对象,如果是可变(mutable)类型,比如列表,修改其中一个,另一个必定改变

    如果是不可变类型(immutable),比如字符串,修改了其中一个,另一个并不会变

    浅拷贝:数据半共享(复制其数据独立内存存放,但是只拷贝成功第一层)

    l1 = [1,2,3,[11,22,33]]
    l2 = l1.copy()
    print(l2) #[1,2,3,[11,22,33]]
    l2[3][2]='aaa'
    print(l1) #[1, 2, 3, [11, 22, 'aaa']]
    print(l2) #[1, 2, 3, [11, 22, 'aaa']]
    l1[0]= 0
    print(l1) #[0, 2, 3, [11, 22, 'aaa']]
    print(l2) #[1, 2, 3, [11, 22, 'aaa']]
    print(id(l1)==id(l2)) #Flase

    比较一下l2与l1的内存地址:False,说明,l2在内存中已经独立出一部分复制了l1的数据,但是只是浅拷贝,第二层的数据并没有拷贝成功,而是指向了l1中的第二层数据的内存地址,所以共享内存‘相当于‘’等号赋值’‘,所以就会有l2中第二层数据发生变化,l1中第二层数据也发生变化

    如图,这就是浅拷贝的原理,l2拷贝l1的时候只拷贝了他的第一层,也就是在其他内存中重新创建了l1的第一层数据,但是l2无法拷贝l1的第二层数据,也就是列表中的列表,所以他就只能指向l1中的第二层数据

    由此,当修改l1中第二层数据的时候,浅拷贝l1的l2中的第二层数据也随之发生改变

    深拷贝:数据完全不共享(复制其数据完完全全放独立的一个内存,完全拷贝,数据不共享)

     深拷贝就是完完全全复制了一份,且数据不会互相影响,因为内存不共享。

    深拷贝的方法有

    导入模块

    import copy
    l1 = [1, 2, 3, [11, 22, 33]]
    # l2 = copy.copy(l1)  浅拷贝
    l2 = copy.deepcopy(l1)
    print(l1,'>>>',l2)
    l2[3][0] = 1111
    print(l1,">>>",l2)

    由此可见深拷贝就是数据完完全全独立拷贝出来一份。不会由原先数据变动而变动

  • 相关阅读:
    HTML5 文件上传
    Vue-Router模式、钩子
    网络基础协议随笔
    Vue-Router基础使用
    vue中mixin的一点理解
    纯css3跑马灯demo
    Charles使用笔记
    提个醒。。。
    本机未装Oracle数据库时Navicat for Oracle 报错:Cannot create oci environment 原因分析及解决方案
    easyUI datagrid 清空
  • 原文地址:https://www.cnblogs.com/pythonlearing/p/9745081.html
Copyright © 2020-2023  润新知