函数模块开个头
内容回顾
# 1. 什么是文件? 指一种操作系统为我们提供的操作硬盘的功能.
# 2. 为什么要用文件?
我们对文件的读写操作都会被操作系统转换为读写硬盘的操作
# 3. 怎么使用文件?
# 1. 由应用程序向操作系统发起系统调用open(...)
# 2. 操作系统打开该文件,并返回一个文件句柄给应用程序
# 3. 应用程序将文件句柄赋值给变量f
ps:在操作文件后,一定要记得f.close()
# 4. 文件的操作模式
控制文件读写操作的模式
# r(默认的):只读
# w:只写
# a:只追加写
控制文件读写内容的操作
# t模式(默认的):读写都是以字符串为单位的,只适用于文本文件,必须指定encoding参数
# b模式:读写都是以bytes为单位的,适用于所有文件,一定不能指定encoding参数
# 大前提:t,b模式均不能单独使用,必须与r/w/a其中的一个结合使用
# t(默认):文本模式
# t模式:如果我们指定的文件打开模式为r/w/a,其实就是默认rt/wt/at
操作文件的方法
#掌握
f.read() #读取所有内容,光标移动到文件末尾
f.readline() #读取一行内容,光标移动到第二行首部
f.readlines() #读取每一行内容,存放于列表中
# f.read()与f.readlines()d都是将内容一次性读入内存,这样如果容过大时会导致内存溢出,如果要全部读入内容,就需要分多次读入
r模式,w模式以及a模式的使用
# r模式:只读模式,如果文件不存在则报错,文件存在则文件指针位于文件的开头
# w模式:只写模式,如果文件不存在则创建空文档,文件存在则清空,文件指针处于文件开头
# a模式,在打开了文件不关的情况下,连续的write写入,新写入的内容永远跟在后面,这一点与w模式相同
# 不同的是,在打开了文件之后关闭然后重新打开的情况下,a模式永远写在后面,切=且不会清空原文件内容
主动控制文件内指针移动
# 0 模式:默认的模式,该模式代表指针移动的字节数是以文件开头为参照的
# 1 模式:
# 2 模式:
内容概述
1.文件修改的两种方式
2.函数
3.模块
今日内容详细
1.文件修改的两种方式
# 文件a.txt内容如下
张一蛋 山东 179 49 12344234523
李二蛋 河北 163 57 13913453521
王全蛋 山西 153 62 18651433422
# 执行操作
with open('a.txt',mode='r+t',encoding='utf-8') as f:
f.seek(9)
f.write('<妇女主任>')
# 文件修改后的内容如下
张一蛋<妇女主任> 179 49 12344234523
李二蛋 河北 163 57 13913453521
王全蛋 山西 153 62 18651433422
# 强调:
# 1、硬盘空间是无法修改的,硬盘中数据的更新都是用新内容覆盖旧内容
# 2、内存中的数据是可以修改的
文件对应的是硬盘空间,硬盘不能修改对应着文件本质也不能修改,那我们看到文件的内容可以修改是如何实现的?
我们的思路是将硬盘的文件内容读入内存,然后内存中修改完毕后再覆盖会硬盘
具体的操作方式有两种:
- 文件修改方式一
# 思路:将文件的内容一次性全部读入内存,然后在内存中修改完毕后再覆盖回原文件
# 优点:在文件修改的过程中同一份数据只有一份
# 缺点:会过多的占用内存
with open('a.txt', mode='rt', encoding='utf-8') as f:
data = f.read()
with open('a.txt', mode='wt', encoding='utf-8') as f:
f.write(data.replace('EGON', 'egon'))
- 文件修改方式二
# 思路:以读的方式打开原文件,以写的方式打开另一个临时文件,一行行读取原文件内容,修改完写入临时文件...,删掉原文件,将临时文件重命名为原文件名
# 优点:不会占用过多的内存
# 缺点:在文件修改过程中同一份数据存了两份
import os
with open('a.txt', mode='rt', encoding='utf-8') as f1, \
open('a.txt.swp', mode='wt', encoding='utf-8')as f2:
for line in f1:
f2.write(line.replace('lty', '胡桑'))
os.remove('a.txt')
os.rename('a.txt.swp', 'a.txt')
2.函数
- 什么是函数
函数就是组织好的,可重复复使用的,用来实现单一,或相关功能的代码段.
- 为什么要使用函数
随着程序功能的增多,代码量的增加,这时候如果将所有实现功能的代码放在一起,就会使程序的组织结构不清晰,可读性变差.而且程序中需要频繁使用同一功能时,只能重复编写该功能的实现代码,使代码变得冗长.而且要修改某一功能时,又要花费大量的时间找出定义和使用这段功能的地方进行修改,增加管理和维护的难度.以上.
为了解决这些问题,我们使用函数来作为简化程序设计的方案.
- 定义函数
函数的使用要遵循"先定义,后调用"的原则,函数的定义就相当于事先将函数体代码保存起来,然后将内存地址赋值给函数名,函数名就是对这段代码的引用,与变量的定义类似.如果没有事先定义函数而直接调用,就相当于引用一个不存在的"变量名".
定义函数的语法如下:
def 函数名(参数1,参数2,...): # 也可以没有参数
"""文档描述(对函数的描述)"""
函数体
return 值
# 1. def:定义函数的关键字
# 2. 函数名:函数名指向函数的内存地址,是对函数体代码的引用.函数的命名应该反映出函数的功能
# 3. 括号:括号内定义参数,参数是可有可无的,而且无需指定参数的类型
# 4. 冒号:括号后要加冒号,下一行编写函数体代码时应缩进
# 5. """文档描述""":描述函数的功能,参数介绍等信息的文档,不是必须的,但为了增加函数的可读性,最好加上
# 6. 函数体:由语句和表达式组成
# 7. return值:定义函数的返回值,return也是可有可无的,不带表达式的return相当于返回None
参数是函数的调用者向函数体传值的媒介,若函数体代码逻辑依赖外部传来的参数时就需要定义为参函数
def my_min(x,y):
res=x if x < y else y
return res
否则定义为无参函数
def interactive():
user = input('user>>:').strip()
pwd = input('password>>:').strip()
return (user,pwd)
函数体为pass时,代表什么都不做,称之为空函数,空函数是很有用的,程序在设计的开始阶段,先想好程序都需要完成什么功能,然后把功能都列举出来用pass充当函数体'占位符',这能使程序的体系结构清晰且可读性强
def auth_user():
"""user authentication function"""
pass
- 调用函数与函数返回值
# 定义阶段
def foo():
print('in the foo')
bar()
def bar():
print('in the bar')
# 调用阶段
foo()
执行结果为:# in the foo
# in the bar
定义阶段函数foo与bar均无语法错误,而在调用阶段调用foo()时,函数foo与bar都早已经存在于内存中了,所以不会有任何问题
按照在程序出现的形式和位置,可以将函数的调用形式分为三种:
# 1. 语句形式:
foo()
# 2. 表达式形式:
m = my_min(1,2) # 将调用函数的返回值赋值给X
n = 10*my_min(1,2) # 将调用函数的返回值乘以10的结果赋值给n
# 3. 函数调用作为参数的形式:
# m= my_min(2,3)作为函数my_min的第二个参数,实现了取1,2,3中的较小者赋值给m
m = my_min(1,my_min(2,3))
如果需要将函数体代码执行的结果返回给调用者,则需要用到return,return后无值或直接省略return,则默认返回None,return的返回值无类型限制,且可以将多个返回值放到一个元组内
def test (x,y,z):
... return x,y,z # 等同于return(x,y,z,)
...
res = test(1,2,3)
print(res)
# (1,2,3)
return是一个函数结束的标志,函数内可以有多个return,但执行一次函数就结束了,并把return后定义的值作为本次调用的结果返回
3.模块
- 什么是模块
模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py,模块可以被别的程序引入,以此使用该模块中的函数等功能,这也是使用python标准库的方法
-
为什么要用模块
1.拿来主义,提高开发效率
2.减少代码冗余
-
模块的类别以及来源
# 模块分为四种通用的类别
1.使用python编写的.py文件
2.已经编译为共享库或DLL的C或C++扩展
3.把一系列模块组织到一起的文件夹(ps:文件夹下有一个__init__.py文件,该文件夹被称为"包")
4.使用C编写并链接到python解释器的内置模块
# 模块的三种来源:
1. python自带的模块/库
内置模块
标准库
2.第三方的库
3.自定义库
- 如何使用模块
首次导入模块会做三件事:
1.执行源代码文件
2.产生一个新的名称空间用于存放原文件执行过程中产生的名字
3.在当前执行文件所在的名称空间中得到一个名字foo,该名字指向新创建的模块名称空间,若要引用模块名称空间中的名字,需要加上该前缀,如下
import foo # 导入模块foo
a = foo.x # 引用模块foo中变量x的值赋值给当前空间中的名字a
foo.get() # 调用模块foo的get函数
foo.change() # 调用模块foo中的change函数
obj = foo.Foo() # 使用模块foo的类Foo来实例化,进一步可以执行obj.func()
加上foo.作为前缀就相当于指名道姓地说明要引用foo名称空间中的名字,所以肯定不会与当前执行文件所在名称空间中的名字相冲突,并且若当前执行文件的名称空间中存在x,至西宁foo.get()或foo.change()操作的都是源文件中的全局变量x
需要强调一点是,第一次导入模块已经将其加载到内存空间了,之后的重复导入会直接引用内存中已存在的模块,不会重复执行文件,通过import sys,打印sys.modules的值可以看到内存中已经加载的模块名。
# 1.在Python中模块也属于第一类对象,可以进行赋值、以数据形式传递以及作为容器类型的元素等操作。
#2、模块名应该遵循小写形式,标准库从python2过渡到python3做出了很多这类调整,比如ConfigParser、Queue、SocketServer全更新为纯小写形式。
- 一些常用模块:random模块
import random
print(random.random())#(0,1)----float 大于0且小于1之间的小数
print(random.randint(1,3)) #[1,3] 大于等于1且小于等于3之间的整数
print(random.randrange(1,3)) #[1,3) 大于等于1且小于3之间的整数
print(random.choice([1,'23',[4,5]]))#1或者23或者[4,5]
print(random.sample([1,'23',[4,5]],2))#列表元素任意2个组合
print(random.uniform(1,3))#大于1小于3的小数,如1.927109612082716
item=[1,3,5,7,9]
random.shuffle(item) #打乱item的顺序,相当于"洗牌"
print(item)
# 生成随机验证码
import random
def make_code(n):
res=''
for i in range(n):
s1=chr(random.randint(65,90))
s2=str(random.randint(0,9))
res+=random.choice([s1,s2])
return res
print(make_code(4))
- OS模块
os.getcwd() # 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname") # 改变当前脚本工作目录;相当于shell下cd
os.curdir # 返回当前目录: ('.')
os.pardir # 获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2') # 可生成多层递归目录
os.removedirs('dirname1') # 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname') # 生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname') # 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname') # 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove() # 删除一个文件
os.rename("oldname","newname") # 重命名文件/目录
os.stat('path/filename') # 获取文件/目录信息
os.sep # 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep # 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep # 输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name # 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command") # 运行shell命令,直接显示
os.environ # 获取系统环境变量
os.path.abspath(path) # 返回path规范化的绝对路径
os.path.split(path) # 将path分割成目录和文件名二元组返回
os.path.dirname(path) # 返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path) # 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path) # 如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path) # 如果path是绝对路径,返回True
os.path.isfile(path) # 如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) # 如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]]) # 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path) # 返回path所指向的文件或者目录的最后存取时间
os.path.getmtime(path) # 返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) # 返回path的大小
- suprocess模块
import subprocess
'''
sh-3.2# ls /Users/egon/Desktop |grep txt$
mysql.txt
tt.txt
事物.txt
'''
res1=subprocess.Popen('ls /Users/jieli/Desktop',shell=True,stdout=subprocess.PIPE)
res=subprocess.Popen('grep txt$',shell=True,stdin=res1.stdout,
stdout=subprocess.PIPE)
print(res.stdout.read().decode('utf-8'))
#等同于上面,但是上面的优势在于,一个数据流可以和另外一个数据流交互,可以通过爬虫得到结果然后交给grep
res1=subprocess.Popen('ls /Users/jieli/Desktop |grep txt$',shell=True,stdout=subprocess.PIPE)
print(res1.stdout.read().decode('utf-8'))
#windows下:
# dir | findstr 'test*'
# dir | findstr 'txt$'
import subprocess
res1=subprocess.Popen(r'dir C:\Users\Administrator\PycharmProjects\test\函数备课',shell=True,stdout=subprocess.PIPE)
res=subprocess.Popen('findstr test*',shell=True,stdin=res1.stdout,
stdout=subprocess.PIPE)
print(res.stdout.read().decode('gbk')) #subprocess使用当前系统默认编码,得到结果为bytes类型,在windows下需要用gbk解码

浙公网安备 33010602011771号