Python基础总结--10(模块使用、迭代器、生成器、文件)

一、模块使用

模块就是用一堆代码实现了某个功能的代码集合,python中一个py文件就是一个模块;模块有三种类型:自定义模块,内置模块,第三方模块
1、自定义一个模块

''' 自定义了一个my_math 模块 '''
PI=3.14159
e=2.718
def fibo(n):
    if n==1 or n==0:return 1
    return fibo(n-1)+fibo(n-2)

def factorial(n:int):
    result=1
    for x in range(1,n+1):
        result*=x
    return result

if __name__=="__main__":
    print(PI )
    print(fibo(10))
    print(factorial(5))
#执行该模块后的结果:
'''
3.14159
89
120
'''

注意:
若模块中存在 if name == 'main':
直接执行当前模块,代码块会被执行;如果在别的模块中被导入,代码块不会执行(阻止其他模式使用该模块的代码)
分析:
每一个模块都有一个_ _name_ _属性, 这个属性的默认值是当前模块对应py文件的文件名;当当前模块正被执行(直接)的时候,系统会自动将模块的_ _name_ _属性变成'_ _main_ _'
2、模块的使用
导入模块:代码执行到import的时候,会将import后面的模块的内容执行一遍;当两个模块中含有相同名称函数或者变量的时候,后面一次引入会覆盖前一次引入
(1)import 模块名
将模块中所有的内容都导入,并且可以在当前模块中通过'模块名.'的方式去使用模块中的所有全局变量
(2)from 模块名 import 变量1, 变量2,
将模块中所有的内容都导入,但是只能使用import后面的变量
注意:通过这种方式引入的时候,调用函数时只能给出函数名,不能给出模块名
(3)from 模块名 import *
将模块中所有的内容都导入, 可以直接使用模块中的所有全局变量
重命名:
(1)import 模块名 as 模块的新名字
给模块重命名,使用模块的时候用新的名字来使用
(2)from 模块名 import 变量名1 as 新名1, 变量名2
给部分变量重新命名

import my_math as Math_mine
print(Math_mine.e,Math_mine.PI)
from my_math import *
print(fibo(10))
from my_math import PI as pi,e as E
print(pi,E)

二、迭代器

什么是迭代器
1.什么是迭代器(iter)
迭代器是python中一种容器类的数据类型,属于序列。没有具体的字面量,可以将其他的序列转换成迭代器:iter(序列)
2.迭代器的特点
只能通过next方法去一个一个按顺序获取迭代器中的元素,取出后迭代器中就不存在这个元素了

任何实现了iternext()方法的对象都是迭代器,iter返回迭代器自身,next返回容器中的下一个值;如果容器中没有更多元素了,则抛出StopIteration异常
迭代器的使用

iter1 = iter('abcd')
print(iter1) #返回一个迭代器对象
print(next(iter1)) #获取迭代器的值
print(next(iter1))
iter2 = iter((1, 2, 3))
a = iter2.__next__()  #通过.__next__()方法
print(a)  # 1
list1 = list(iter2)
print(list1)  # [2, 3]
#遍历迭代器
iter1 = iter(['abc', 10, 'name'])
print('=====')
for x in iter1:
    print(x)
print('====')

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

三、生成器

生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅,实质就是函数体中有yield关键字的函数
生成器一定是迭代器(反之不成立),因此任何生成器也是以一种懒加载的模式生成值
从列表推导式说起....
若一个列表为:[1,2,3,4,5,6,7,8,9],要求把每一个元素都翻倍,实现的方式有三种:

#第一种:使用循环
info = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for index,element in enumerate(info):
    info[index] *=2
print(info)
#enumerate()--将一个可遍历的数据对象组合为一个索引序列,同时列出数据和数据下标

#第二种:使用map()函数
info = [1, 2, 3, 4, 5, 6, 7, 8, 9]
a = map(lambda x:x*2,info)
for i in a:
    print(i,end=" ")

#第三种:使用列表推导式
info = [1, 2, 3, 4, 5, 6, 7, 8, 9]
a = [i*2 for i in range(10)]
print(a)

思考:
若列表的数据很大(1000万个元素),创建的时候占用了大量的内存空间,但是又只需要用到前面1000个元,那后面绝大多数元素占用的空间都白白浪费了
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间,在Python中,这种一边循环一边计算的机制,称为生成器:generator
生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器
生成器与一般函数的不同:
(1)生成器函数包含一个或者多个yield
(2)当调用生成器函数时,函数将返回一个对象,但是不会立刻向下执行
(3)像iter()和next()方法等是自动实现的,可以通过next()方法对对象进行迭代
(4)一旦函数被yield,函数会暂停,控制权返回调用者
(5)局部变量和它们的状态会被保存,直到下一次调用
(6)函数终止的时候,StopIteraion会被自动抛出

生成式
生成式就是生成器的一种特殊形式:(变量 for 变量 in 序列)

gen1 = (x*2 for x in range(5))
print('=========')
for item in gen1:
    print(item)
gen2 = ([x, x*2] for x in 'abc')
print(next(gen2))
print('===========')
gen3 = (x for x in range(5) if x%2)
for item in gen3:
    print(item)

生成器函数
也是用def定义的,利用关键字yield一次性返回一个结果,阻塞,重新开始

def gen4(n):
    for x in range(n+1):
        print("第{}次循环:x={}".format(x,x))
        yield x
        if x % 2 :
            yield "{}是奇数".format(x)
        else:
            yield "{}是偶数".format(x)
a=gen4(5) 
print(a) #
print(a.__next__())  #执行到yield关键字,控制权返回调用者,并保持局部变量状态
print(a.__next__())  #从yield关键字开始继续执行,遇到yield关键字再次返回
'''
第0次循环:x=0
0
0是偶数
'''
def gen5(n):
    for x in range(n):
        yield x, 2*x, 3*x
    return "Done"
a=gen5(3)
print(next(a))
print(next(a))
print(next(a))
'''
(0, 0, 0)
(1, 2, 3)
(2, 4, 6)
'''
#思考:如何才能取到返回值Done?
#必须捕获StopIteration错误,返回值包含在StopIteration的value
while True:
    try:
        x=next(a)
        print('generator: ',x)
    except StopIteration as e:
        print("生成器返回值:",e.value)  #生成器返回值: Done
        break

#用生成器计算斐波拉契数列
def fibo(max):
    n,a,b =0,0,1
    while n < max:
        yield b
        a,b =b,a+b
        n = n+1
    return 'done'
for i in fibo(6):
    print(i,end=",")
#创建一个generator后,基本上永远不会调用next(),而是通过for循环来迭代,并且不需要关心StopIteration的错误

四、文件操作

使用文件可以做数据的持久化(本地化) ---> 数据库文件,txt、json,plist,二进制文件
所有文件操作的过程:打开文件 --> 操作文件 --> 关闭文件
文件操作 -- 读写操作
   读 -> 取出文件中的数据
   写 -> 将数据写到文件中
打开文件和关闭文件
open(file, mode='r',encoding=None)
a.file -> 文件路径(必须传参),决定需要打开的是哪个文件
绝对路径(不推荐使用)
相对路径: ./相对路径 (相对路径是相对当前py文件对应的文件夹)
     ./ ---> 当前文件夹
      ../ --> 当前文件夹的上层文件夹
     .../ --> 当前文件夹的上层文件夹的上层文件夹
b.mode -> 文件打开方式(不同的操作对应不同的打开方式)
     'r' --> 以只读的形式打开文件, 文本
     'rb'/'br' --> 读操作,读出来的数据是二进制形式的数据
     'w' --> 以写的形式打开文件(完全覆盖)
     'bw'/'wb' --> 写操作,将二进制数据写入文件
     'a' --> 写操作,追加
c.encoding -> 文本文件的编码方式
    utf-8 :几乎支持所有的语言文字
    gbk : 只支持英文

d.open函数的返回值,就被打开的文件对象

关闭文件: 文件对象.close()

f1 = open('./test1.txt', 'r', encoding='utf-8')
content = f1.read()
print(type(content), content)
content = f1.readline()  
print(type(content), content)# # 返回值为空,该文件打开后已经被读完
content = f1.readlines()
print(type(content), content) # []
f1.close()


f2 = open('./test1.txt', 'w', encoding='utf-8')
f2.writelines(['abc\n', '123\n', 'aaaaa\n'])

with关键字
with open(文件路径,打开方式,encoding=编码方式) as 文件对象:
文件操作代码
说明:打开文件执行操作后自动关闭文件对象,防止操作过程中出现异常导致文件未关闭

with open("./file/libai.txt",'w',encoding='utf-8') as file1:
    file1.write('床前明月光,\n疑是地上霜\n')
with open("./file/libai.txt",'r',encoding='utf-8') as file1:
    content=file1.read()
    print(content)

二进制文件操作
常见的二进制文件:视频、音频、图片、压缩包等
bytes -->字节,python专门用来表示二进制数据类型
注意:二进制文件不能设置文件编码方法(不能给encoding赋值)
作用:下载或上传文件

with open('./file/chengfabiao.png','rb') as file2:
    content=file2.read()
    print(type(content),content)
with open('./file/chengfabiao_copy.png','wb') as file2:
    file2.write(content)

思考:读取或写入数据量为10G的文件,如何做?

你可能感兴趣的:(Python基础总结--10(模块使用、迭代器、生成器、文件))