python基础 (v3.6.6)
day03
1. 函数
日常写的线性代码不具有复用性,可以使用函数,提高代码的复用性
内置函数: print()、 input()、 range()等
自定义函数:人为构造的函数
def stu(name):
print('我叫'+name)
stu('tom') #调用函数
def stu(name):
return '我叫'+name
print(stu('lily')) #调用函数
无参函数:
def 函数名():
执行数据
return 返回值
def plus():
a,b = 5,6
return a + b
print(plus()) #调用函数
注意:在实际应用中,无参函数很少使用,课程主要讲有参函数
有参函数:
def 函数名(参数列表):
执行数据
return 返回值
def plus2(a,b):
return a + b
print(plus2(3,4)) #调用函数
在python中,不可变的数据类型有 str, tuple, int, float, set。
可变的数据类型有list,dict
可变、不可变,可以使用id()打印数据的地址,修改后再打印数据地址比对
python调用函数时传递的参数类型,分为以下几种:位置参数、关键字参数、默认参数、不定长参数
1-1. 位置参数
def who(name,age):
return '我是{},今年{}岁'.format(name,age)
print(who('tom',20)) →: 我是tom,今年20岁
print(who(20,'tom')) →: 我是20,今年tom岁
print(who(name='tom',age=20)) →: 我是tom,今年20岁
print(who(age=20,name='tom')) →: 我是tom,今年20岁
调用函数时,传入的两个值按照位置顺序依次赋给参数
1-2. 默认参数
def who(name,age=18):
return '我是{},今年{}岁'.format(name,age)
print(who('tom')) →: 我是tom,今年18岁
print(who('tom',25)) →: 我是tom,今年25岁
print(who(name='tom',age=25)) →: 我是tom,今年25岁
注意:默认参数需要放到后面,且默认参数必须指向不变对象
def def3(name = 'lily',age = 25):
return '我是%s,今年%d岁'%(name,age)
name1 = 'tom'
age1 = 666
print(def3()) →:我是lily,今年25岁
print(def3(name1)) →:我是tom,今年25岁
print(def3(name1,age1)) →:我是tom,今年666岁
#print(def3(name,age)) #这里不知道name,age是什么,所以会报错
1-3. 可变参数(不定长参数)
# 加了星号 * 的参数会以元组(tuple)的形式导入
def test(a,*b):
return a,b
print(test(2)) →: (2, ())
print(test(2,666)) →: (2, (666,))
print(test(2,666,888)) →: (2, (666, 888))
例:给定一组数字 a,b,c …… ,请计算a2 + b2 + c2 + ……
由于参数个数不确定,可以把a,b,c……作为一个list或tuple传进来。
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
nums = [1, 2, 3]
print(calc(*nums)) →: 14
注: *nums表示把nums这个list的所有元素作为可变参数传进去
可变参数允许传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple
1-4.关键字参数(可以扩展函数的功能)
#加了两个星号 ** 的参数会以字典的形式导入
def test(a,**b):
return a,b
print(test(2)) →: (2, {})
print(test(2,i=666)) →: (2, {'i': 666})
print(test(2,i=666,j=888)) →: (2, {'i': 666, 'j': 888})
b = {'i':666,'j':888}
print(test(2,**b)) →: (2, {'i': 666, 'j': 888})
def person(name, age, **kw):
if 'city' in kw: # 检查如果有city参数,就怎么样
pass
print('name:', name, 'age:', age, 'other:', kw)
extra = {'city': 'emei', 'job': 'tester'}
person('Jack', 24, **extra) →:name: Jack age: 24 other: {'city': 'emei', 'job': 'tester'}
关键字参数允许传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict
使用*args和**kw是Python的习惯写法,也可以用其他参数名
1-5. 命名关键字参数(限制关键字参数的名字)
命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数
def person(name, age, *, city, job):
print(name, age, city, job) # 本例中,只接收city和job作为关键字参数
命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错
person('Jack', 24, city='emei', job='tester') →:Jack 24 emei tester
person('Jack', 24, 'Beijing', 'Engineer') →:报错
命名关键字参数可以有缺省值,从而简化调用
def person(name, age, *, city='Beijing', job):
print(name, age, city, job)
person('Jack', 24, job='Engineer') →:Jack 24 Beijing Engineer
由于命名关键字参数city具有默认值,调用时,可不传入city参数
若函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了
def person(name, age, *args, city, job):
print(name, age, args, city, job)
命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。
1-6.参数组合
定义函数,可用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,5种参数可组合使用
但参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
def f2(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
f1(1, 2) →:a = 1 b = 2 c = 0 args = () kw = {}
f1(1, 2, c=3) →:a = 1 b = 2 c = 3 args = () kw = {}
f1(1, 2, 3, 'a', 'b') →:a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
f1(1, 2, 3, 'a', 'b', x=99) →:a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
f2(1, 2, d=99, ext=None) →:a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
虽然可以组合多达5种参数,但不要同时使用太多的组合,否则函数接口的可理解性很差
1-7. 局部变量和全局变量
局部变量:定义在函数内部的变量,只能在其被声明的函数内部访问。
全局变量:定义在函数外部的变量,可以在整个程序范围内访问。
total = 25
def test(a,b):
total = a+b
return total
#调用函数,打印局部变量
print(test(5,3)) →: 8
#打印全局变量
print(total) →: 25
在函数内修改全局变量:
total = 25
def test(a,b):
global total #引入全局变量
print("全局变量是",total) →: 全局变量是25
total = a+b
return total
#调用函数,打印局部变量
print(test(5,3)) →: 8
#打印全局变量
print(total) →: 8
注意:在函数内部引入变量,使用global
1-8. 匿名函数
匿名函数,是不使用def语句这样标准的形式来定义一个函数。
匿名函数的好处是,用完一次就可以扔掉;使用lambda不需要考虑命名的问题。
语法: lambda 参数: 表达式
#将匿名函数赋值给变量
func = lambda a,b: a+b
#通过变量来调用匿名函数
print(func(2,5)) →: 7
#以下示例对比普通函数和匿名函数(最大值函数)
#普通函数
def max(a,b):
if a>b:
return a
else:
return b
print(max(5,3))
#匿名函数
func = lambda a,b: a if a>b else b
print(func(5,3))
注意:不一定非要使用lambda函数;任何能够使用它们的地方,都可以定义一个单独的普通函数来进行替换。
我们将它们用在需要封装特殊的、非重用代码上,避免令我的代码充斥着大量单行函数。
通常情况下,匿名函数很少单独使用,会结合python的高阶函数进行使用,
比如:map(),reduce(),filter(),zip()这些函数。
补:pass是占位符,当函数体不知道写什么时,可以用pass占位,保证程序不报错
2. 模块
在python中,一个.py文件就是一个模块。
模块可以理解为是一个包含了函数和变量的py文件,在程序中引入某个模块,就可以使用其中的函数和变量。
windows下面的文件夹中,包含__init__.py文件的文件夹,称之为: 包
windows下面的文件夹下面的.py文件,称之为:模块
python自带了功能丰富的标准库,另外还有数量庞大的各种第三方库。
语法: import 模块名
from 模块名 import 方法
from time import * # 表示导入time模块下所有方法
import mokuai as mk # 补充: 将模块名别名成mk
2-1. random模块
# randint(),可以在连续整数范围内,随机获取一个整数
import random
num = random.randint(1,5)
print(num) # 随机打印1~5之间任意整数
# choice(),可以随机获取字符串、列表、元组中的元素
from random import choice
list1 = ["tom",666,"橘子"]
a = choice(list1)
print(a)
#练习:在1到100中随机获取10个唯一的整数
from random import randint
list1 = []
while True:
i = randint(1,100)
if i not in list1:
list1.append(i)
if len(list1) == 10:
break
print(list1)
2-2. os模块
# 1.获取当前的工作目录
import os
print(os.path.abspath('.')) # 运行脚本的工作路径
print(os.getcwd()) # 运行脚本的工作路径
# 2.获取当前文件完整路径
print(os.path.abspath(__file__)) # 模块文件完整路径
# 3.获取上一级路径:os.path.dirname(路径)
print(os.path.dirname(r'C:\test\test1.py')) # 当前文件的上一级路径
print(os.path.dirname(os.getcwd())) # 运行脚本所在的路径的上一级路径
os.path.dirname(__file__) # 模块文件所在路径(win直接当前运行会不识别)
os.path.dirname(os.path.abspath(__file__)) # 模块文件所在路径(常用)
# 4.列出当前文件所属目录下面的所有文件和目录
print(os.listdir())
# 5.判断文件还是文件夹
path1 = "C:\课堂练习\python练习\周末班.py"
path2 = "C:\课堂练习\python练习"
print(os.path.isfile(path1)) # 如果是文件,就返回True
print(os.path.isdir(path2)) # 如果是文件夹,就返回True
# 6.将a,b两个路径连接起来:os.path.join(路径a,路径b)
cur = os.getcwd()
new = os.path.join(cur,'test2.py')
print(new)
# 注意要连接的两个路径,前面路径的末尾、后面路径的开头不能有\
new2 = os.path.join(r'C:\test',r'test2\test3.py')
print(new2)
# 7.创建一个文件夹: os.mkdir("文件夹名称")
os.mkdir("test1") #直接在当前位置创建了一个test1的文件夹
os.mkdir(os.path.join(os.getcwd(),"test")) #一样的效果
# 8.删除文件夹: os.rmdir("文件夹名称")
os.rmdir("./test1")
os.rmdir("test2")
# 9.删除文件: os.remove("文件名")
os.remove("test1.py")
# 10.修改文件名 os.rename(源文件的路径\文件名,目标文件的路径\文件名)
os.rename(r"E:\pywork\新建文本文档.txt",r"E:\pywork\666.txt")
# 11.将一个路径拆分成文件夹路径和文件名字:os.path.split(路径)
path1 = os.path.abspath(__file__)
print(path1) →: C:\课堂练习\python练习\周末班.py
print(os.path.split(path1)) →: ('C:\\课堂练习\\python练习', '周末班.py')
# 12.将一个路径处理成文件名
print(os.path.basename(r"E:\pywork\666.py")) →: 666.py
print(os.path.basename(r"E:\pywork\666.py").split(".")[0]) →: 666
# 13.将一个文件名拆分成名字和后缀(如.py) : os.path.splitext(路径)
path2="python周末班练习题.py"
print(os.path.splitext(path2)) →: ('python周末班练习题', '.py')
# 14.将不规范的路径变成规范的路径:os.path.normpath(路径)
path2="C:\\\课堂练习//python练习/\/周末班.py"
print(os.path.normpath(path2)) →: C:\课堂练习\python练习\周末班.py
2-3. time模块
#导包
import time
# 1.等待固定时长
time.sleep(2) #等待2秒
# 2.获取当前系统时间
# 分别表示星期、月份、日期、时分秒、年份
print(time.ctime()) →: Wed Feb 9 16:29:44 2022
# 时间戳,从1970年1月1日0时0分0秒到现在的秒数
print(time.time()) →: 1644395384.006
# 时间元组,分别表示年、月、日、时、分、秒、一周第几日 (0是周一)、一年第几日、
夏令时标志(1表示执行夏令时,0表示不执行夏令时,-1表示不清楚是否执行)
print(time.localtime())
→: time.struct_time(tm_year=2022, tm_mon=2, tm_mday=9,
tm_hour=16, tm_min=29, tm_sec=44, tm_wday=2, tm_yday=40, tm_isdst=0)
# 3.将日期转换为字符串:strftime("格式",时间)
print(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())) →: 2022-02-09 16:58:38
# 补充(了解):
①
from time import *
print(strftime('%F')) →:2021-11-03
print(strftime('%X')) →:10:02:38
print(strftime('%Y-%m-%d')) →:2021-11-03
print(strftime('%H:%M:%S')) →:10:02:38
②
from datetime import date,timedelta
print(date.today()) →:2021-11-03
print(date.today() + timedelta(-3)) →:2021-10-31
endtime = str(date.today()) + ' 12:12:12'
print(endtime) →:2021-11-03 12:12:12
2-4. 自定义模块
自定义模块,模块里面的内容要自己写,然后在需要使用模块里面的方法时,再把模块导进来用。
自定义模块calc1、calc2、clac3、calc4的内容都一样的:
def jia():
return a+b
def jian():
return a-b
def cheng():
return a*b
def chu():
return a/b
# 1.自定义模块,与脚本文件在同一个文件夹下
from calc1 import jia
print(jia(3,5))
注:脚本文件test.py跟自定义模块calc1.py都在同一个文件夹下
# 2.自定义模块在脚本文件的子文件夹下
from haha.calc2 import jia,jian
print(jian(5,3))
注:脚本文件是test\lianxi.py,自定义模块是test\haha\calc2.py
# 3.自定义模块在脚本文件的父级文件夹下,可以使用相对路径
import sys
sys.path.append('../') #导入临时路径
from calc import *
print(cheng())
注:脚本文件是liu\test\lianxi.py,自定义模块是liu\calc.py
# 4.自定义模块跟脚本文件离得太远,用绝对路径
import sys
sys.path.append(r'D:\test')
from calc import *
print(chu())
注:脚本文件是C:\liu\lianxi.py,自定义模块是D:\test\calc.py
3. 文件读写:text文本的读写
3-1. 文件的打开和关闭
语法:
open("文件的路径","打开的方式")
文件的句柄.close()
f = open("./test1.txt",'w') #打开文件
f.close() #关闭文件
print(f.closed) #判断是否关闭文件,如果关闭,返回True
打开方式:
'r',只读模式,文件必须存在,不存在则返回异常FileNotFoundError,默认值
'w',覆盖写模式,文件不存在则创建,存在则完全覆盖,不可读
'x',创建写模式,文件不存在则创建,存在则返回异常FileExistsError
'a',追加写模式,文件不存在则创建,存在则在文件最后追加内容
't',文本文件模式,默认值
'+',打开一个文件进行更新(可读可写)
'r+',可读,可写,不能创建文件,会从后面追加内容
'w+',打开文件用于读写。如果文件存在则打开,并从头编辑,删除原有内容。不存在则创建。
'a+',打开文件用于读写。如果文件存在,打开时是追加模式。文件不存在则创建。
'b',二进制文本模式,以二进制模式打开文件,而不是以文本模式,不能指定编码
3-2.往文件里写入内容 write()、writelines()
# 打开文件
f = open("./test1.txt",'w+')
str1 = "人生苦短\n我用python\n"
list1 = ["人生苦短\n","我用python\n"]
list2 = ["tom",666]
# 将一个字符串写入文件: write()
f.write(str1)
# 将字符串或列表写入文件:writelines()
f.writelines(str1) #将字符串写入文件
f.writelines(list1) #可以将字符串形式的列表、元组、集合写入文件
f.writelines(list2) #不支持非字符串形式的列表等,会报错
f.close() #关闭文件
print("文件是否被关闭",f.closed)
3-3.读取文件的信息
f = open("./test12.txt",'r+') #打开文件
print(f.read(3)) #读取前3个字符,注意换行符不会显示,但会占据空间
print(f.read()) #读取文件全部内容
print(f.readline()) #读取文件第一行
print(f.readlines()) #读取所有的内容,并以列表的形式保存
f.close() #关闭文件
# 练习:把下面的文件内容写到一个文件里面,然后读取文件的内容并计算平均分
文件内容如下:
小白,88
小黑,90.5
小黄,
小花,33
#写入文件内容
f = open("./test1.txt","w")
str1 = "小白,88\n小黑,90.5\n小黄,\n小花,33"
f.write(str1)
f.close()
print("文件是否关闭:",f.closed)
#读取文件
f = open("./test1.txt","r")
res = f.readlines()
print(res)
total = 0
for i in res:
# print(i)
# strip()移除字符串两端的空格,split()以指定字符切割字符串,切割后保存为列表
res2 = i.strip().split(",")[1]
# print(res2)
if res2 != "":
total = total + float(res2)
#平均分
avg = total / len(res)
print(avg)
3-4.使用上下文管理关键字with方法
上面的操作,都要使用.close()方法来关闭文件,
使用 with open .. as 方法,就可以不需要单独进行关闭,系统会自动关闭文件。
# 写入文件
with open("./test1.txt","w+") as f:
f.write("人生苦短,\n我用Python\n")
print("检查文件是否关闭:",f.closed)
# 读取文件
with open("./test1.txt","r") as f:
res = f.read()
print(res)
print("检查文件是否关闭:",f.closed) # False,没关闭
print("检查文件是否关闭:",f.closed) # True,已经关闭
# 练习:将test0000~test9999共一万行的账号写入txt文件。
with open("test01.txt","w+") as f: # w覆盖写,可创建
for i in range(10000):
# print("test%04d"%i)
f.write("test%04d\n"%i)