show | version | enable_checker |
---|---|---|
step |
1.0 |
true |
- 这次我们要从头回顾函数的各个方面
- 最开始我们还不知道什么是函数
- 函数就是套路
- 一段代码需要反复执行
- 我们把他封装成一个代码块
- 起一个名字
- 代表这段代码
- 以后我们就可以通过调用(call)函数
- 来反复执行这段代码
- 函数也可以接受一些参数
- 函数定义的时候
- 有形参列表
- 调用的时候
- 有实参可以传进来
- 这经历了一个赋值的过程
- 将实参的值赋给函数的形参
- 实参的值一般是一个对象的引用
- 字符串、整型、浮点型传进函数内部后
- 不会影响外面的变量
- 列表、集合等容器如果再函数内部改变后
- 会影响外面的指向同一地址的变量
- 参数是函数内部的局部变量
- 局部变量和全局变量有不同的作用域(scope)
- 主程序中定义的是模块全局(global)可见的
- 函数中定义的和函数形参是函数局部(local)可见的
- 如果同名
- 局部的会屏蔽(shadow)全局的
- 可以将局部变量声明为全局(global)
- 就可以在主程序使用局部变量了
- 函数是一个函数类的对象
- code object里面有这个函数的各种信息
- 函数名
- 内部变量数量和元组
- 字节码
- 还可以把函数对象作为一个实参
- 传递给别的函数的形参
- 变量名都是a
- 但是可以用名字空间进行区分
- 我们有很多变量名来自于内建(
__builtins__
)
- python本来就有好多的包
- 可以方便我们使用
- 我们自己也能打包
- 一个文件夹里面可以有多个py模块
- 文件夹下面的
__init__.py
就是初始化模块的模块 - 会在一开始执行
- 还可以为模块和函数写文档字符串
- 然后把文件或文件夹放进$PYTHONPATH
- 就可以反复调用了
- 模块里面有主程序
__main__.py
- 运行模块就是运行主程序
- 也可以在py文件中直接判断
- 通过判断
__main__==__name__
- 有些代码是只有顶级的时候才执行的
- 作为导入模块不需要执行这些代码
- 每个函数都会有返回值
- 一般是函数运行的结果
- 如果没有返回值
- 那么函数在执行完最后一条语句之后
- 默认返回的一个
NoneType
的值None
- 重写是旧的覆盖新的
- 把原来的抹去
- 重载是同一个函数名
- 不同的参数数量或类型
- 调用的时候可以根据形参情况进入相应的函数体
- 画松树可以分成几步来完成
- 参数也可以不止一个
- 比如修改树冠的颜色
- 还可以
- 为树冠设置默认值绿色
- 树冠大小设置默认值5
- 用的是argparse这个包
- 引用这个包之后
- 可以为python定义各种参数
- 控制参数
- 类型
- 范围
- 默认值等等
- 函数自身的嵌套调用
- 函数的递归调用
- 我们了解了调用栈上的帧
- 可以输出frame对象的内容
- 观察栈帧
- 可以用VizTracer观察栈帧的情况
- 递归在数学上很完美
- 但是对于调用堆栈消耗很大
- 如何比较了两者呢?
- 了解了timeit可以计数
- 递归有太多的重复运算
- 这些重复运算可以用lru_cache消除
- 函数内部可以定义函数
- 将具体操作放在函数中的函数里面
- 可以屏蔽外面的干扰
- 内部函数的变量可以通过nonlocal被外层代码访问
- 总结三种作用域
- local 本地可见 (默认)
- global 全局可见
- nonlocal 非本地可见(上一层函数也可见)
- 函数内部的同名函数变量会屏蔽(shadow)外层的变量名
enclosing_function
中的_fibo
不是外面全局的_fibo
enclosing_function
中的_fibo
屏蔽了外面全局的_fibo
- 这是持续集成
- 先求的是因数集合
- 然后在因数集合中找到质因数
- 质因数求解过程中发现开方的好处
- 大幅度提高效率
- 然后再求解最大公约数的时候
- 发现了辗转相除法的好处
- 极大的提升了效率
- 有的时候模块还需要打破重组
- python虽然是动态类型编程语言
- 但是也有类型提示
def get_factor_set(num: int) -> set:
s: set = {1}
for i in range(2, num + 1):
if num % i == 0:
s.add(i)
return s
def gcd(n1: int, n2: int) -> set:
s1: set = get_factor_set(n1)
s2: set = get_factor_set(n2)
gcd: set = s1.intersection(s2)
return max(gcd)
print(gcd(3600,4096))
- 可以进行静态类型检查(mypy)
- 还可以静态语言分析(pylint)
- 使得代码符合pep8
- 形参可以分成
- 纯位置
- 两可
- 纯关键字
- 还可以接受元组*args作为形参
- 实现不定长的位置参数列表
- 还可接受字典**kwargs作为形参
- 实现不定长的关键字参数列表
- lambda表达式会形成一个匿名函数
- 直接写在实参的位置
- 简单明确
- 我们这次学习了很多函数相关的内容
- 函数就是套路
- 可以让代码一次次地执行
- 用形参来接收实参
- 完成套路之后返回
- 函数可以层层嵌套
- 也就是层层套路
- 甚至递归函数
- 通过函数我们实现了代码的复用
- 各种类型都有很多的函数作为辅助
- 下次我们看点什么?🤔
- 下次再说👋