1 函数概述

06-06. 函数概述

在一个完整的项目中,某些功能会反复的使用,那么会将功能封装成函数,当我们要使用功能的时候直接调用函数即可。
本质:函数就是对功能的封装。
函数的优点:

  • 简化代码结构,增加了代码的复用度(重复使用的程度);
  • 如果想修改某些功能或者调试某个BUG,修改对应的函数即可。

    1.1 定义函数

    def 函数名(参数列表):
    语句
    return 表达式

  • 函数代码块以def关键字开始;

  • 函数名遵循标识符规则;
  • ():是参数列表的开始和结束;
  • 参数列表(参数1,参数2,……,参数n):任何传入函数的参数和变量必须放在圆括号之间,用逗号分隔。函数从函数的调用者那里获取的信息;
  • 冒号:函数内容(封装的功能)以冒号开始,并且缩进;
  • 语句:函数封装的功能;
  • return:一般用于结束函数,并返回信息给函数的调用者;
  • 表达式:即为要返回给函数的调用者的信息。
    注意:最后的return 表达式,可以不写,相当于return None。
  1. #定义了一个无参无返回值的函数
  2. def myPrint():
  3. print("sunck is a very good man!")
  4. print("sunck is a nice man!")
  5. print("sunck is a handsome man!")
  6. myPrint()
  7. myPrint()

函数的调用
函数名(参数列表)

  • 函数名:是要使用功能的函数名字;
  • 参数列表:函数的调用者给函数传递的信息,如果没有参数,小括号也不能省略。
    函数调用的本质是实参给形参赋值的过程。

参数

06-07. 最简单的函数、函数的参数、函数的返回值

形参(形式参数):定义函数时小括号中的变量,本质是变量,参数必须按顺序传递,个数目前要对应(有默认值时可以不对应)。
实参(实际参数):调用函数时给函数传递的数据,本质是值。

  1. def myPrint(str, age):
  2. print(str, age)
  3. myPrint("sunck is a good man", 18)

返回值

  1. def mySum(num1, num2):
  2. #将结果返回给函数的调用者
  3. return num1 + num2
  4. #执行完return语句,该函数就结束了,return后面的代码不执行
  5. print("**********")
  6. res = mySum(1, 2)
  7. print(res)

参数传递
值传递:传递的不可变类型,如string、tuple、number是不可变的。

  1. def func1(num):
  2. print(id(num))
  3. num = 10
  4. print(id(num))
  5. temp = 20
  6. print(id(temp))
  7. #-->8791555639568
  8. func1(temp)
  9. #num = temp
  10. #-->8791555639568
  11. #-->8791555639248
  12. print(temp)
  13. #-->20

image.png

引用传递:传递的可变类型,如list、dict、set是可变的。

  1. def func(lis):
  2. lis[0] = 100
  3. li = [1,2,3,4,5]
  4. func(li)
  5. print(li)
  6. #-->[100, 2, 3, 4, 5]

image.png

相同值的变量,地址一样。

  1. a = 10
  2. b = 10
  3. print(id(a), id(b))
  4. #-->8791472146384 8791472146384
  5. c = 20
  6. d = 30
  7. print(id(c), id(d))
  8. #-->8791472146704 8791472147024
  9. d = c
  10. print(id(c), id(d))
  11. #-->8791472146704 8791472146704

关键字参数
概念:允许函数调用时参数的顺序与定义时不一致。

  1. def myPrint(str, age):
  2. print(str, age)
  3. #使用关键字参数
  4. myPrint(age = 18, str = "sunck is a good man")

默认参数
调用函数时,如果没有传递参数,则使用默认参数。要用默认参数,最好将默认参数放到最后。

  1. def myPrint(str, age = 18):
  2. print(str, age)
  3. myPrint("kaige")

不定长参数
概念:能处理比定义时更多的参数。
加了星号(*)的变量存放所有未命名的变量参数,如果在函数调用时没有指定参数,它就是一个空元组。

  1. def func(name, *args):
  2. print(name)
  3. print(type(args))
  4. for x in args:
  5. print(x)
  6. func("sunck", "good", "nice", "handsom")
  7. #-->sunck
  8. #--><class 'tuple'>
  9. #-->good
  10. #-->nice
  11. #-->handsom
  12. def mySum(*l):
  13. sum = 0
  14. for i in l:
  15. sum += i
  16. return sum
  17. print(mySum(1,2,3,4,5,6,7))
  18. #-->28

*代表键值对的参数字典,和所代表的意义类似。

  1. def func(**kwargs):
  2. print(kwargs)
  3. print(type(kwargs))
  4. func(x=1, y=2, z=3)
  5. #-->{'x': 1, 'y': 2, 'z': 3}
  6. #--><class 'dict'>
  7. def func3(*args, **kwargs):
  8. pass #代表一个空语句

1.2 匿名函数

概念:不使用def这样的语句定义函数,使用lambda来创建匿名函数。
特点:

  • lambda只是一个表达式,函数体比def简单;
  • lambda的主体是一个表达式,而不是代码块,仅仅只能在lambda表达式中封装简单的逻辑;
  • lambda函数有自己的命名空间,且不能访问自由参数列表之外的或全局命名空间的参数;
  • 虽然lambda是一个表达式且看起来只能写一行,与C和C++内联函数不同。
    格式:

lambda 参数1,参数2,……,参数n:expression

  1. sum = lambda num1, num2:num1 + num2
  2. print(sum(1,2))

2 装饰器

07-01. 装饰器

2.1 简单装饰器

概念:是一个闭包,把一个函数当做参数,返回一个替代版的函数,本质上就是一个返回函数的函数。

  1. #简单的装饰器
  2. def func1():
  3. print("sunck is a good man")
  4. def outer(func):
  5. def inner():
  6. print("*******************")
  7. func()
  8. return inner
  9. #f是函数func1的加强版本
  10. f = outer(func1)
  11. f()
  12. #-->*******************
  13. #-->sunck is a good man

2.2 复杂一点装饰器

  1. def say(age):
  2. print("sunck is %d years old" % (age))
  3. def outer(func):
  4. def inner(age):
  5. if age < 0:
  6. age = 0
  7. func(age)
  8. return inner
  9. say = outer(say)
  10. say(-10)
  1. def outer(func):
  2. def inner(age):
  3. if age < 0:
  4. age = 0
  5. func(age)
  6. return inner
  7. #使用@符号将装饰器应用到函数
  8. #@python2.4支持使用@符号
  9. @outer #相当于say = outer(say)
  10. def say(age):
  11. print("sunck is %d years old" % (age))
  12. say(-10)

2.3 通用装饰器

  1. def outer(func):
  2. def inner(*args, **kwargs):
  3. #添加修改的功能
  4. print("&&&&&&&&&&&&&")
  5. return func(*args, **kwargs)
  6. return inner
  7. @outer #say = outer(say)
  8. def say(name, age): #函数的参数力理论上是无限制的,但实际上最好不要超过6、7个
  9. print("my name is %s, I am %d years old" % (name, age))
  10. return "aaaa"
  11. say("sunck", 18)

3 偏函数

07-03. 偏函数、变量作用域

3.1 自己定义偏函数

  1. print(int("1010", base = 2))
  2. #-->10
  3. #偏函数
  4. def int2(str, base = 2):
  5. return int(str, base)
  6. print(int2("1011"))
  7. #-->11

3.2 使用functools偏函数

  1. import functools
  2. #把一个参数固定住,形成一个新的函数
  3. int3 = functools.partial(int, base = 2)
  4. print(int3("1011"))
  5. #-->11

4 递归

4.1 概述

09-01. 递归

递归函数:一个会调用自身的函数称为递归函数;
递归调用:一个函数,调用了自身,称为递归调用。

凡是循环能干的事,递归都能干。

方式:

  • 写出临界条件;
  • 找这一次和上一次的关系;
  • 假设当前函数已经能用,调用自身计算上一次的结果,再求出本次的结果。
    输入一个数(大于等于1),求1+2+3+……+n的和 ```python

    循环

    def sum(n): sum = 0 for x in range(1, n + 1):
    1. sum += x
    return sum

递归

def sum(n): if n == 1: return 1 else: return n + sum(n - 1) res = sum(5) print(“res =”, res)

  1. <a name="d485564c"></a>
  2. ## 4.2 栈
  3. > _09-_02. 队列与栈
  4. ![](https://cdn.nlark.com/yuque/0/2022/jpeg/21926274/1657548907406-2a4f85ab-c0bf-4450-88f7-36925e5cbf3f.jpeg)
  5. 以下仅用程序模拟栈的思想:
  6. ```python
  7. #模拟栈结构
  8. stack = []
  9. #压栈(向栈里存数据)
  10. stack.append("A")
  11. print(stack)
  12. stack.append("B")
  13. print(stack)
  14. stack.append("C")
  15. print(stack)
  16. #出栈(在栈里取数据)
  17. res1 = stack.pop()
  18. print("res1 =", res1)
  19. print(stack)
  20. res2 = stack.pop()
  21. print("res2 =", res2)
  22. print(stack)
  23. res3 = stack.pop()
  24. print("res3 =", res3)
  25. print(stack)
  26. #-->['A']
  27. #-->['A', 'B']
  28. #-->['A', 'B', 'C']
  29. #-->res1 = C
  30. #-->['A', 'B']
  31. #-->res2 = B
  32. #-->['A']
  33. #-->res3 = A
  34. #-->[]

4.3 队列

04 - 函数 - 图3

  1. import collections
  2. #创建一个队列
  3. queue = collections.deque()
  4. print(queue)
  5. #进队(存数据)
  6. queue.append("A")
  7. print(queue)
  8. queue.append("B")
  9. print(queue)
  10. queue.append("C")
  11. print(queue)
  12. #出队(取数据)
  13. res1 = queue.popleft()
  14. print("res1 =", res1)
  15. print(queue)
  16. res2 = queue.popleft()
  17. print("res2 =", res2)
  18. print(queue)
  19. res3 = queue.popleft()
  20. print("res3 =", res3)
  21. print(queue)
  22. #-->deque([])
  23. #-->deque(['A'])
  24. #-->deque(['A', 'B'])
  25. #-->deque(['A', 'B', 'C'])
  26. #-->res1 = A
  27. #-->deque(['B', 'C'])
  28. #-->res2 = B
  29. #-->deque(['C'])
  30. #-->res3 = C
  31. #-->deque([])

4.4 目录遍历

使用递归思路

09-03. 目录遍历(递归)

  1. #使用递归方法
  2. import os
  3. def getAllDirRE(path, sp = ""):
  4. #得到当前目录下所有的文件
  5. filesList = os.listdir(path)
  6. #处理每一个文件
  7. sp += " "
  8. for fileName in filesList:
  9. #判断是否是路径(用绝对路径)
  10. fileAbsPath = os.path.join(path, fileName)
  11. if os.path.isdir(fileAbsPath):
  12. print(sp + "目录:", fileName)
  13. #递归调用
  14. getAllDirRE(fileAbsPath, sp)
  15. else:
  16. print(sp + "普通文件:", fileName)
  17. getAllDirRE(r"C:\Users\John\Desktop\temp\dir")

使用压栈思路

09-04. 目录遍历(栈-深度遍历)

深度遍历思路:
image.png

  1. import os
  2. def getAllDirDE(path):
  3. stack = []
  4. stack.append(path)
  5. #处理栈,当栈为空的时候结束循环
  6. while len(stack) != 0:
  7. #从栈里取出数据
  8. #[]
  9. dirPath = stack.pop()
  10. #print(dirPath)
  11. #目录下所有文件
  12. filesList = os.listdir(dirPath)
  13. #print(filesList)
  14. #处理每一个文件,如果是普通文件则打印出来,如果是目录则将该目录的地址压栈
  15. for fileName in filesList:
  16. fileAbsPath = os.path.join(dirPath, fileName)
  17. if os.path.isdir(fileAbsPath):
  18. #是目录就压栈
  19. print("目录:" + fileName)
  20. stack.append(fileAbsPath)
  21. #["B", "E", "F"]
  22. else:
  23. #打印普通文件
  24. print("普通:" + fileName)
  25. getAllDirDE(r"C:\Users\John\Desktop\temp\dir")

使用队列思路(广度遍历)

09-05. 目录遍历(队列-广度遍历)1

广度遍历思路:
image.png

  1. import os
  2. import collections
  3. def getAllDirQU(path):
  4. queue = collections.deque()
  5. #进队
  6. queue.append(path)
  7. while len(queue) != 0:
  8. #出队数据
  9. dirPath = queue.popleft()
  10. #找出所有的文件
  11. filesList = os.listdir(dirPath)
  12. for fileName in filesList:
  13. #绝对路径
  14. fileAbsPath = os.path.join(dirPath, fileName)
  15. #判断是否是目录,是目录就进队,不是就打印
  16. if os.path.isdir(fileAbsPath):
  17. print("目录:" + fileName)
  18. queue.append(fileAbsPath)
  19. else:
  20. print("普通文件:" + fileName)
  21. getAllDirQU(r"C:\Users\xlg\Desktop\Python-1704\day09\temp\dir")

5 Time

5.1 time

09-06. 目录遍历(队列-广度遍历)2、time模块1

UTC(世界协调时间):格林尼治天文时间,世界标准时间,在中国来说是UTC+8。

时间的表示形式:

  • 时间戳
    以整型或浮点型表示时间的一个以秒为单位的时间间隔。这个时间间隔的基础值是从1970年1月1日零点开始算起。
  • 元组
    一种Python的数据结构表示,这个元组有9个整型内容: year、month、day、hours、minutes、seconds、weekday、Julia day、flag (1 或 -1 或0)。
  • 格式化字符串 | %a | 本地(locale)简化星期名称 | | —- | —- | | %A | 本地完整星期名称 | | %b | 本地简化月份名称 | | %B | 本地完整月份名称 | | %c | 本地相应的日期和时间表示 | | %d | 一个月中的第几天(01-31) | | %H | 一天中的第几个小时(24小时制,00-23) | | %I | 第几个小时(12小时制,01-12) | | %j | 一年中的第几天(001-366) | | %m | 月份(01-12) | | %M | 分钟数(00-59) | | %p | 本地am或者pm的相应符 | | %S | 秒(01-61) | | %U | 一年中的星期数。(00-53星期天是一个星期的开始。)第一个星期天之前的所有天数都放在第0周 | | %w | 一个星期中的第几天(0-6,0是星期天) | | %W | 和%U基本相同,不同的是%W以星期一为一个星期的开始。 | | %x | 本地相应日期 | | %X | 本地相应时间 | | %y | 去掉世纪的年份(00-99) | | %Y | 完整的年份 | | %Z | 时区的名字(如果不存在为空字符) | | %% | ‘%’字符 |

image.png

  1. import time
  2. #返回当前时间的时间戳,浮点数形式,不需要参数
  3. c = time.time() #1618067951.5776775
  4. #将时间戳转为UTC时间元组
  5. t = time.gmtime(c) #time.struct_time(tm_year=2021, tm_mon=4, tm_mday=10, tm_hour=15, tm_min=19, tm_sec=11, tm_wday=5, tm_yday=100, tm_isdst=0)
  6. #将时间戳转为本地时间元组
  7. b = time.localtime(c) #time.struct_time(tm_year=2021, tm_mon=4, tm_mday=10, tm_hour=23, tm_min=19, tm_sec=11, tm_wday=5, tm_yday=100, tm_isdst=0)
  8. #将本地时间元组转成时间戳
  9. m = time.mktime(b) #1618067951.0
  10. #将时间元组转成字符串
  11. s = time.asctime(b) #Sat Apr 10 23:19:11 2021
  12. #将时间戳转为字符串 time.asctime(time.localtime(time.time()))
  13. p = time.ctime(c) #Sat Apr 10 23:19:11 2021
  14. #将时间元组转换成给定格式的字符串,参数2为时间元组,如果没有参数2,默认转当前时间
  15. q = time.strftime("%Y-%m-%d %X", b) #2021-04-10 23:19:11
  16. #将时间字符串转为时间元组
  17. w = time.strptime(q, "%Y-%m-%d %X") #time.struct_time(tm_year=2021, tm_mon=4, tm_mday=10, tm_hour=23, tm_min=19, tm_sec=11, tm_wday=5, tm_yday=100, tm_isdst=-1)
  18. #延迟一个时间,整型或者浮点型
  19. time.sleep(4)

time.perfcounter()可以理解为计时器,返回两次执行的间隔。
“09-_08. time模块3、datetime”讲解的为time.clock(),新版本已弃用。

  1. import time
  2. #返回当前程序的cup执行时间
  3. #Unix系统始终返回全部的运行时间
  4. #windows从第二次开始,默认都是以第一个调用此函数的开始间戳作为基数
  5. tis1 = time.perf_counter()
  6. print("%d" % tis1) #0
  7. print("等待3秒......")
  8. time.sleep(3)
  9. tis2 = time.perf_counter()
  10. print("%d" % tis2) #3
  11. print(tis2-tis1) #2.9980309
  12. time.sleep(2)
  13. tis3=time.perf_counter()
  14. print("%d" % tis3) #5
  15. print(tis3-tis1) #5.018696
  16. print(tis3-tis2) #2.0206651000000004

异常:在pycharm中加Python3.8环境,调用time.clock出异常:AttributeError module 'time' has no attribute 'clock'
解决方案:用time.perf_counter()替换。

5.2 Datetime

09-08. time模块3、datetime

datetime比time高级了不少,可以理解为datetime基于time进行了封装,提供了各位使用的函数,datetime模块的接口更直观,更容易调用。
模块中的类:

datetime 同时有时间和日期
timedelta 主要用于计算时间的跨度
tzinfo 时区相关
time 只关注时间
date 只关注日期
  1. import datetime
  2. #获取当前时间
  3. d1 = datetime.datetime.now()
  4. print(d1)
  5. #-->2021-04-11 18:22:37.489621
  6. print(type(d1))
  7. #--><class 'datetime.datetime'>
  8. #获取指定时间
  9. d2 = datetime.datetime(1999, 10, 1, 10, 28, 25, 123456)
  10. print(d2)
  11. #-->1999-10-01 10:28:25.123456
  12. #将时间转为字符串
  13. d3 = d1.strftime("%Y-%m-%d %X")
  14. print(d3)
  15. #-->2021-04-11 18:22:37
  16. print(type(d3))
  17. #--><class 'str'>
  18. #将格式化字符串转为datetime对象
  19. #注意:转换的格式要与字符串一致
  20. d4 = datetime.datetime.strptime(d3, "%Y-%m-%d %X")
  21. print(d4)
  22. #-->2021-04-11 18:22:37
  23. d5 = datetime.datetime(1999, 10, 1, 10, 28, 25, 123456)
  24. d6 = datetime.datetime.now()
  25. d7 = d6 - d5
  26. print(d7)
  27. #-->7863 days, 7:54:12.381766
  28. print(type(d7))
  29. #--><class 'datetime.timedelta'>
  30. #间隔的天数
  31. print(d7.days)
  32. #-->7863
  33. #间隔天数除外的秒数
  34. print(d7.seconds)
  35. #-->28452

5.3 calendar

09-09. datetime、calendar

  1. import calendar
  2. #返回指定某年某月的日历
  3. print(calendar.month(2017, 7))
  4. #返回指定年的日历
  5. print(calendar.calendar(2017))
  6. #闰年返回True,否则返回False
  7. print(calendar.isleap(2000))
  8. #-->True
  9. #返回某个月的weekday的第一天和这个月所有的天数
  10. print(calendar.monthrange(2017, 7))
  11. #-->(5, 31)
  12. #返回某个月以每一周为元素的列表
  13. print(calendar.monthcalendar(2017,7))
  14. #-->[[0, 0, 0, 0, 0, 1, 2], [3, 4, 5, 6, 7, 8, 9], [10, 11, 12, 13, 14, 15, 16], [17, 18, 19, 20, 21, 22, 23], [24, 25, 26, 27, 28, 29, 30], [31, 0, 0, 0, 0, 0, 0]]