今天已经开始接触Python高级的知识了,依旧照例,依旧进行我们的知识回顾与总结,废话不多说,开始我们的战斗!
1、包和模块
在我们接触到一个新名词时,我们第一个要做的事情就是要明白这个名称是什么?那什么是包和模块呢?其实这在我们Python中很常见。
**包(package):在python中,用来包裹模块的文件夹。**
在python中,文件夹是可以当成包使用的,但包并不是文件夹!!
在python中,如果一个文件夹中存在__init__.py这个模块文件的话,这个文件夹就是包,init.py一般用来初始化文件
**模块(module):xx.py文件, 保存是要执行或者使用代码。**
了解了包和模块的概念,我们要知道它们的使用方法,这里说一下常见的导包方式。
1、import package.module
2、import package.module as alias
3、**from package import module** (推荐这种导包方式)
4、from package import module as alias
5、from package.package... import module as alias
6、from package import * # 通配所有
2、is和==的区别
is和==有什么区别呢?
首先两者都是判断变量的,但是!
is判断的是两个变量的内存地址
==判断的两个变量的值
小整形缓存区(-5~256)
3、深浅拷贝
接下来说说深浅拷贝,这里我们要了解三个概念,分别是赋值、浅拷贝、深拷贝。接下来我分别说下这三个知识点。
1、赋值
赋值:主要的操作,栈内存的复制。
赋值在Python中就太常见了,我们很多操作都需要用到赋值,如果不赋值,有时我们就无法完成我们程序。
>>>a = "宋同学" #把宋同学赋值给a
>>>b = a #把a的值赋给b
>>>b == a #a等于b
>>>true #结果正确
这就是赋值。
2、浅拷贝
接下来来说说深拷贝和浅拷贝。实现要明白两者的本质区别,这里我自己通俗的理解就是。
浅拷贝的对象与源对象两者还是有联系的,但是深拷贝的对象与源对象则是完全没有联系,是一个新的对象。
如果是一个列表:ls2 = ls.copy()
浅拷贝对象,并不是完全把对象拷贝,而是仅仅拷贝了第一层对象,如果对象中存储有子对象,那么两者还是有联系的。
3、深拷贝
深拷贝使用递归的方式完成的拷贝,这样,两个对象之间没有任何关系,并不存在联系。
拷贝对象,对象是存储在堆中的,拷贝堆内存,需要得到第二个一样的对象,复制拷贝对象的效率最高。
当然,我们Python中为了提供对象拷贝,专门为大家提供了一个copy模板。
copy.copy #浅拷贝,相当于列表中cpoy方法
理论上讲解是这样的,可能还不够明显的变现出两者的区别,在这里,用一个展示来变现下两者的区别。
>>>ls = [2020,4,10] #创建一个列表
>>>ls1 =copy.copy(ls) #浅拷贝
>>>ls2 =copy.deepcopy(ls) #深拷贝
>>>ls.append(4) #往列表ls追加4
>>>ls1 #查看列表1
>>>[2020,4,10]
>>>ls2 #查看列表2
>>>[2020,4,10]
>>>ls #查看列表ls
>>>[2020,4,10,4]
>>>ls is ls1
>>>False
>>>ls is ls2
>>>False
没有嵌套时,深浅拷贝都是复制堆里的数据,产生新的地址。
列表深浅拷贝,都产生新的数据堆,浅拷贝嵌套的第二层指向同一个数据,深拷贝是递归拷贝,产生新的数据堆。
元组浅拷贝,只拷贝第一层,第一层是元组,元组不可变,只有一个内存,嵌套的第二层指向同一个数据。
深拷贝是递归拷贝,所有的都拷贝了。
在这里特表要注意的两点!
1、需要将当前对象拷贝的时候,一般建议拷贝为浅拷贝,(效率高,内存占有少)
2、如果说,就是需要完全分离,请使用深拷贝。
最后的结论:
元组、字符串、数值这些不可变类型,所有深浅拷贝后,永远只有一份内存==注意特殊情况,如元组中的存在可变类型的元素
4、生成器
接下来说说生成器,这里要说几个东西,分别是列表推导器、列表生成器、以及函数转换为列表生成器和yield关键字的作用。
1、列表推导器
[ x for x in range(101)]
[ i for i in range(101) if i % 2 == 0]
[ i*j for i in range(10) for j in range(10)]
这个功能非常的强大,可以快速得到需要的列表。
缺点:如果一个列表特别的庞大,这样所有的元素直接初始化到内存中,引起大量无用元素占有内存问题
>>>[i for i in range(6)]
>>>[0,1,2,3,4,5]
>>>[i for i in range(6) if i%2==1]
>>>[1,3,5]
2、列表生成器(list generator)
列表推导式 —> 生成器
[ 列表推导式 ] --> (列表推导式) # 就会变成一个列表推导式,使用全局函数next,没调用一次next,返回下一个值,直到最后抛出异常。
(1)
(2)也可以使用循环迭代generator
(3)生成器对象也存在一个__next__魔方方法,等价于next全局函数
优点:节约内存
3、函数转换为列表生成器
当列表生成时,需要大量代码来完成时,不可能使用列表推导式,一般使用函数完成,如:(斐波那契数列)
斐波那契数列:
从第三个元素开始,每一个元素是前两个元素之和,【 如果函数中使用yield关键字,那么这个函数的返回值就是一个生成器】
4、yield关键字作用
1、 具有return的功能,能够返回一个函数的值。
2、 当一个函数出现yield,那么这个函数就被调用执行,而是返回值是一个生成器。
3、 next它返回值,不断地返回被yield的值
yield值之后,会记住当前位置,下一次next函数调用生成器的时候,会在记住的位置继续执行。
def fibonacii(num):
first, second = 1, 1
index = 0
while index < num:
first, second = second, first + second
# 如果函数中使用yield关键字,那么这个函数的返回值就是一个生成器
yield first
index += 1
if __name__ == '__main__':
res = fibonacii(5)
print(res)
#<generator object fibonacii at
0x000001603925DFC0>使用yield关键字装饰的函数,
当调用函数时,函数本身并不会调用,而是将函数转换为
一个生成器返回
print(next(res))
print(next(res))
print(next(res))
print(next(res))
print(next(res))
5、迭代器
迭代是访问容器元素的一种方式
可迭代对象(Iterable)
以后需要迭代一个对象
from collections.abc import Iterable, Iterator
t = 对象
if isinstance(t, Iterable):
for i in t: # 迭代对象
else:
print("对不起,该对象不能迭代")
【迭代器】
在python,能够被全局函数next调用,并且返回下一个值的对象,就是迭代器。
可迭代对象不一定是迭代器,迭代器都是可迭代对象
结论:
1、凡是可作用于 for 循环的对象都是 Iterable 类型;
2、凡是可作用于 next() 函数的对象都是 Iterator 类型
3、可迭代对象不一定是迭代器,迭代器都是可迭代对象
4、集合数据类型如 list 、 dict 、 str 等是 Iterable 但不是 Iterator ,
5、不过可以通过iter() 函数获得一个 Iterator 对象。
6、目的是在使用迭代器的时候,减少内存的占用。
6、闭包
闭包(closure)
闭包是一种现象,是若数据类型编程语言所特有的现象。
JavaScript(js)时时刻刻在使用闭包
概念: 能够在函数内部调用其他函数变量的现象就闭包
函数包裹函数的现象,就叫做闭包
作用:让外层函数常驻内存,有可能垃圾无法回收,让局部变量全局化
def father():
'''
这个函数就是一个闭包
'''
print("这个是一个闭包")
a = 10
def son():
print("这个是里面函数的代码")
b = 20
print(a + b)
return son #返回一个地址
res = father() #调用father(),并没有调用son()
print(res) #<function father.<locals>.son at 0x000002E8022E8AE8>是return返回的地址
res()
还有几个内容,我放到Python高级(二)中来说,今天又是奥里给的一天,大家加油!明日可期。
下一篇Python高级(二)中会说到装饰器、动态语言的特性、垃圾回收机制、常见的内置模块、常见的全局函数和正则表达式。
我们下一篇文章见,那么我不在的日子,祝你早好,午好,晚好,我们下次见了,bye~