python的深浅拷贝和对象赋值

  • Python中对象的赋值都是进行对象引用(内存地址)传递,对象本身和内部元素都是引用的方式;
  • 使用copy.copy(),可以进行对象的浅拷贝,它复制了对象,但对于对象中的元素,依然使用原始的引用;
  • 如果需要复制一个容器对象,以及它里面的所有元素(包含元素的子元素),可以使用copy.deepcopy()进行深拷贝;对象和内部元素都是不同的;
  • 对于非容器类型(如数字、字符串、和其他’原子’类型的对象)没有被拷贝一说
  • 如果元祖变量只包含原子类型对象,则不能深拷贝,比如:(“python”, “cs”, []),因为[]是原子类对象,所以不能进行深拷贝。

具体可参考,此文

set和list区别,为何set更快

list是有序的,可重复,元素类型可以不一样,通过下标来访问不同位置的元素;常用的一些函数有pop(), append(), extend(), insert()
set通常是用来进行去重,内容无序不可重复;常用的函数有add(), update(), remove()。
同时set的效率要比list高。List转Set基本用不了什么时间,所以如果有需要求(集合,列表等)的并集和交集的时候,最好使用Set。
查找效率:set>dict>list(数据显示上list的效率比前面两个慢很多倍)。
dict是用来存储键值对结构的数据的,set其实也是存储的键值对,只是默认键和值是相同的。Python中的dict和set都是通过散列表来实现的。下面来看与dict相关的几个比较重要的问题:

  • dict中的数据是无序存放的
  • 操作的时间复杂度,插入、查找和删除都可以在O(1)的时间复杂度
  • 键的限制,只有可哈希的对象才能作为字典的键和set的值。可hash的对象即python中的不可变对象和自定义的对象。可变对象(列表、字典、集合)是不能作为字典的键和st的值的。
  • 与list相比:list的查找和删除的时间复杂度是O(n),添加的时间复杂度是O(1)。但是dict使用hashtable内存的开销更大。为了保证较少的冲突,hashtable的装载因子,一般要小于0.75,在python中当装载因子达到2/3的时候就会自动进行扩容。

https://blog.csdn.net/liuweiyuxiang/article/details/98943272
hash原理:比如取余数,加常数,再取余数等方式

python的装饰器,生成器和迭代器

  • 迭代器是一个可以记住遍历位置的对象,在遍历字符串、列表、或者元组的时候非常有用。
  • 生成器是函数中包含yield语句的一类特殊函数。
  • 装饰器的灵活性很强,可以为一个对象添加新的功能,或者给函数插入相关的功能。

    迭代器

    迭代器概述

    迭代器是一个更抽象的概念,任何对象,如果它的类有next方法和iter方法返回自己本身,对于string、list、dict、tuple等这类容器对象,使用for循环遍历是很方便的。在后台for语句对容器对象调用iter()函数,iter()是python的内置函数。iter方法需要返回对象本身,即self,而next方法需要返回下一个数据,如果没有数据了,则会抛出一个StopIteration异常。

1)可迭代对象包含迭代器
2)如果一个对象拥有iter方法,其是可迭代对象;如果一个对象拥有__next_方法,其就是迭代器
3)定义可迭代对象,必须实现
iter方法;定义迭代器,必须实现iter方法和next__方法
来了来了,我们接下来用代码去实现一下迭代器的用法

可以直接作用于for循环的数据类型有以下几种:
一类是集合数据类型,如list,tuple,dict,set,str等
一类是generator ,包括生成器和带yeild的generator function

  • 这些可以 直接作用于for循环的对象统称为可迭代对象:Iterable
  • 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

    iter()函数 创建迭代器

    iter(iterable)#一个参数,要求参数为可迭代的类型
    把list、dict、str等Iterable变成Iterator可以使用iter()函数:
    你可能会问,为什么list、dict、str等数据类型不是Iterator?

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

小结

  • 凡是可作用于for循环的对象都是Iterable类型;
  • 凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
  • 集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

    创建一个迭代器(类)

  • 把一个类作为一个迭代器使用需要在类中实现两个方法 iter() 与 next() 。

  • 如果你已经了解的面向对象编程,就知道类都有一个构造函数,Python 的构造函数为 init(), 它会在对象初始化的时候执行
  • iter() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 next() 方法并通过 StopIteration 异常标识迭代的完成。 ```python from itertools import islice class Fib: def init(self):
    1. self.prev = 0
    2. self.curr = 1
    def iter(self):
      return self
    
    def next(self):
      self.prev,self.curr = self.curr,self.prev+self.curr
      return self.curr
    
    f = Fib() print(list(islice(f ,0,10)))

``` [1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
StopIteration
StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 next() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。

内置迭代器工具

比如 itertools 函数返回的都是迭代器对象

  • count无限迭代器
  • cycle 无限迭代器,从一个有限序列中生成无限序列
  • itertools的子模块 islice 控制无限迭代器输出的方式

生成器

生成器(Generator)是创建迭代器的简单而强大的工具。它们写起来就像是正规的函数,只是在需要返回数据的时候使用 yield 语句。每次 next()被调用时,生成器会返回它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)。生成器的内部也声明了: iternext方法,所以生成器也可以说是一个特殊的迭代器。

应用场景

  • 列表所有数据都在内存中,如果有海量数据的话将会非常耗内存。
  • 如:仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
  • 在Python中,这种一边循环一边计算的机制,称为生成器:generator
  • generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
  • 简单一句话:我又想要得到庞大的数据,又想让它占用空间少,那就用生成器

列表生成式的[]改成()

如果要一个一个打印出来,可以通过next()函数(or next())获得generator的下一个返回值.generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象:

通过使用yield关键字定义

生成器对象是通过使用yield关键字定义的函数对象,因此,生成器也是一个函数。生成器用于生成一个值得序列,以便在迭代器中使用。
yield 语句是生成器中的关键语句,生成器在实例化时并不会被执行,而是等待调用其next()方法才开始运行。并且当程序运行完yield语句后就会“吼(hold)住”,即保持当前状态且停止运行,等待下一次遍历时才恢复运行。

生成器在Python中是一个非常强大的编程结构,可以用更少地中间变量写流式代码,此外,相比其它容器对象它更能节省内存和CPU,当然它可以用更少的代码来实现相似的功能。现在就可以动手重构你的代码了,但凡看到类似

装饰器

装饰器:本质是函数(装饰其他函数)就是为其他函数添加附加功能。它可以在让其他函数在不需要做任何代码的变动的前提下增加额外的功能。 装饰器的返回值也是一个函数的对象
使用场景:它经常用于有切面需求的场景。 比如:插入日志、性能测试、事务处理、缓存、权限的校验等场景 有了装饰器就可以抽离出大量的与函数功能本身无关的雷同代码并发并继续使用.
原则:

  • 1 不能修改被装饰的函数的源代码
  • 2 不能修改被装饰的函数的调用方式

实现装饰器知识储备:

  • 1 函数即“”变量“”
  • 2 高阶函数a 把一个函数名当做实参传给另一个函数 b 返回值中包含函数名

高阶函数+嵌套函数 = 装饰器

类装饰器

没错,装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的call方法
https://blog.csdn.net/sunchengquan/article/details/84494101
https://zhuanlan.zhihu.com/p/285155201
https://blog.csdn.net/happygjcd/article/details/103519479
https://www.cnblogs.com/tianyiliang/p/7811041.html

python字典的内部实现

分析为何GIL带来影响