1. 高阶函数

  • 接收函数作为参数,或者将函数作为返回值返回的函数就是高阶函数 ```python def add(x, y, f): return f(x) + f(y)

print(add(-5, 6, abs))

11

  1. - **lambda 表达式也叫匿名函数**,lambda 表达式简化了函数定义的书写形式,使代码更为简洁,使函数的定义方式更为直观,更容易理解。
  2. ```python
  3. sum = lambda x, y : x + y
  4. print("lambda result =", sum(12, 13))
  5. --------------------
  6. lambda result = 25
  7. =============
  8. print((lambda a, b: a + b)(10, 20))
  9. ---------
  10. 30
  11. ===================
  12. # filter() 需要传递两个参数 按照你设定的规则,过滤出你想要的数据
  13. # 1. 传递一个函数
  14. # 2. 传递一个需要过滤的序列(可迭代的)
  15. # print(list(filter(fun1, list1)))
  16. list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  17. result = lambda i: i % 2 == 0
  18. print(list(filter(result, list1)))
  19. --------------------------
  20. [2, 4, 6, 8, 10]

2. 闭包

  • 将函数作为返回值也是高阶函数我们也称为闭包
  • 闭包的好处
    • 通过闭包可以创建一些只有当前函数能访问的变量
    • 可以将一些私有数据藏到闭包中
  • 行成闭包的条件
    • 函数嵌套
    • 将内部函数作为返回值返回
    • 内部函数必须要使用到外部函数的变量
  • Python 的垃圾回收机制,垃圾回收是 Python 自带的功能,并不需要程序员去手动管理内存。

其中引用计数法是最简单直接的,但是需要维护一个字段且针对交叉引用无能为力。
标记清除算法主要是为了解决引用计数的交叉引用问题,该算法的缺点就是需要扫描整个堆的所有对象,有点浪费性能。
而分代回收算法的引入则完美解决了标记清除算法需要扫描整个堆对象的性能浪费问题。该算法也是建立在标记清除基础之上的。
最后我们可以通过 gc.collect() 手动触发 GC 的操作。

  1. # python 垃圾回收机制
  2. # 变量不被销毁
  3. def func_out(num1):
  4. a = 1
  5. def func_inner(num2):
  6. result = num1 + num2
  7. print('result = ', result)
  8. return func_inner
  9. f = func_out(1)
  10. print(f)
  11. f(2)
  12. print(f(2))
  13. f(3)
  14. -------------------
  15. <function func_out.<locals>.func_inner at 0x0000028749C4EC10>
  16. result = 3
  17. result = 3
  18. None
  19. result = 4
  20. ====================================
  21. # 变量不可被更改
  22. # 让外部变量可以修改
  23. def func_out(num1):
  24. def func_inner(num2):
  25. # 告诉解释器,此处使用的是外部变量num1
  26. nonlocal num1
  27. # 这里的本意是要修改外部变量num1的值,实际上是重新进行了赋值
  28. num1 = 10
  29. result = num1 + num2
  30. print(result)
  31. print(num1)
  32. func_inner(2)
  33. print(num1)
  34. return func_inner
  35. f = func_out(1) # 函数对象是func_out 函数调用是func_out()
  36. ----------------------
  37. 1
  38. 12
  39. 10

3. 装饰器的引入

  • 我们可以直接通过修改函数中的代码来完成需求,但是会产生以下一些问题
    • 如果修改的函数多,修改起来会比较麻烦
    • 不方便后期的维护
    • 这样做会违反开闭原则(ocp)
      • 程序的设计,要求开发对程序的扩展,要关闭对程序的修改 ```python def fun1(): print(‘我是fun1函数’)

def add(a, b): return a + b

def mul(a, b): return a * b

函数嵌套

将内部函数作为返回值返回

内部函数必须要使用到外部函数的变量

def fun(fn, args, **kwargs): print(‘函数开始执行’) r = fn(args, **kwargs) print(r) print(‘函数执行完毕’)

fun(add, 1, 2)

函数开始执行 3 函数执行完毕

  1. <a name="2w6l8"></a>
  2. ## 4. 装饰器的使用
  3. - 通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展
  4. - 在开发中,我们都是通过装饰器来扩展函数的功能的
  5. ```python
  6. def fn():
  7. print('我是fn函数')
  8. def fun_out(fun, *args, **kwargs):
  9. def fun_inner(*args, **kwargs):
  10. print('函数开始执行')
  11. r = fun(*args, **kwargs)
  12. print(r)
  13. print('函数执行完毕')
  14. def fun1():
  15. pass
  16. return fun_inner
  17. # @fun_out 等价于 f=fun_out(fun)
  18. # f = fun_out(add, 1, 2) # f = fun_inner
  19. # f()
  20. # 贴吧进行评论的功能, 评论之前是不是得先登录
  21. @fun_out # 语法糖
  22. def fun():
  23. print('进行评论')
  24. fun()
  25. @fun_out
  26. def add(a, b):
  27. return a + b
  28. add(1, 2)
  29. a = 1
  30. s = '%s' % '我不知道'
  31. --------------------
  32. 函数开始执行
  33. 进行评论
  34. None
  35. 函数执行完毕
  36. 函数开始执行
  37. 3
  38. 函数执行完毕


PEP8规范编写代码

PEP8: Python代码风格指南

PEP8 提供了 Python 代码的编写约定. 本节知识点旨在提高代码的可读性, 并使其在各种 Python 代码中编写风格保持一致.

  1. 缩进使用4个空格, 空格是首选的缩进方式. Python3 不允许混合使用制表符和空格来缩进.
  2. 每一行最大长度限制在79个字符以内.
  3. 顶层函数、类的定义, 前后使用两个空行隔开.
  4. import 导入

导入建议在不同的行, 例如:

  1. import os
  2. import sys

不建议如下导包

  1. import os, sys

但是可以如下:

  1. from subprocess import Popen, PIPE
  1. 导包位于文件顶部, 在模块注释、文档字符串之后, 全局变量、常量之前. 导入按照以下顺序分组:

标准库导入
相关第三方导入
本地应用/库导入
在每一组导入之间加入空行

  1. Python 中定义字符串使用双引号、单引号是相同的, 尽量保持使用同一方式定义字符串. 当一个字符串包含单引号或者双引号时, 在最外层使用不同的符号来避免使用反斜杠转义, 从而提高可读性.

  2. 表达式和语句中的空格:

避免在小括号、方括号、花括号后跟空格.
避免在逗号、分好、冒号之前添加空格.
冒号在切片中就像二元运算符, 两边要有相同数量的空格. 如果某个切片参数省略, 空格也省略.
避免为了和另外一个赋值语句对齐, 在赋值运算符附加多个空格.
避免在表达式尾部添加空格, 因为尾部空格通常看不见, 会产生混乱.
总是在二元运算符两边加一个空格, 赋值(=),增量赋值(+=,-=),比较(==,<,>,!=,<>,<=,>=,in,not,in,is,is not),布尔(and, or, not)
避免将小的代码块和 if/for/while 放在同一行, 要避免代码行太长.

  1. if foo == 'blah': do_blah_thing()
  2. for x in lst: total += x
  3. while t < 10: t = delay()
  1. 永远不要使用字母 ‘l’(小写的L), ‘O’(大写的O), 或者 ‘I’(大写的I) 作为单字符变量名. 在有些字体里, 这些字符无法和数字0和1区分, 如果想用 ‘l’, 用 ‘L’ 代替.

  2. 类名一般使用首字母大写的约定.

  3. 函数名应该小写, 如果想提高可读性可以用下划线分隔.

  4. 如果函数的参数名和已有的关键词冲突, 在最后加单一下划线比缩写或随意拼写更好. 因此 class_ 比 clss 更好.(也许最好用同义词来避免这种冲突).

  5. 方法名和实例变量使用下划线分割的小写单词, 以提高可读性.

作业

  1. 请使用装饰器实现已存在的函数的执行所花费的时间。
  • time模块 ```python import time

def calculation(fun, args, **kwargs): def time_computing(args, kwargs): # 计算程序fun()所用时间 time_start = time.perf_counter() fun(*args, kwargs) time_end = time.perf_counter() print(f’程序执行所用时间’, time_end - time_start) print(‘——————————————————————————‘) return time_computing

@calculation def add(a, b): #定义加法 a 与 b之间所有数的和 sum = a for i in range(a, b): sum += i print(f’{a}与{b}之间数的总和 = ‘, sum) return add

add(1, 10**5) # 调用函数计算加法总和

@calculation def power(m, n): # m的n次幂 power = m for i in range(n): power = n print(f’{m}*{n} =’,power_)

power(10, 100)

@calculation def factorial(n): #定义阶乘 n! result = 1 for i in range(1, n+1): result *= i print(f’{n}! =’, result)

factorial(10**3) #调用函数计算阶乘

output:

1与100000之间数的总和 = 4999950001

程序执行所用时间 0.004474300000000004

10**100 = 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

程序执行所用时间 2.089999999999731e-05

1000! = 402387260077093773543702433923003985719374864210714632543799910429938512398629020592044208486969404800479988610197196058631666872994808558901323829669944590997424504087073759918823627727188732519779505950995276120874975462497043601418278094646496291056393887437886487337119181045825783647849977012476632889835955735432513185323958463075557409114262417474349347553428646576611667797396668820291207379143853719588249808126867838374559731746136085379534524221586593201928090878297308431392844403281231558611036976801357304216168747609675871348312025478589320767169132448426236131412508780208000261683151027341827977704784635868170164365024153691398281264810213092761244896359928705114964975419909342221566832572080821333186116811553615836546984046708975602900950537616475847728421889679646244945160765353408198901385442487984959953319101723355556602139450399736280750137837615307127761926849034352625200015888535147331611702103968175921510907788019393178114194545257223865541461062892187960223838971476088506276862967146674697562911234082439208160153780889893964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

程序执行所用时间 0.0004294999999999993

```