Python 函数学习篇

记录于 10.5
强烈推荐看原文章:Python 学习笔记 - 10.5

函数用法与底层分析

  • 可重用的程序代码块
  • 注重逻辑的一致性,也即功能单一

函数大致分为:

  • 内置函数
  • 标准库函数
  • 第三方函数
  • 用户自定义函数

如何创建自定义函数?语法如下:

  • def funcName(para1, para2):
    • Code block

函数也是一个对象,在def语句后初始化一个对象,对象具有 ID 、 类型 、 值 三要素。因此也同样,初始化后 ID 绑定到函数名,也即标识符上。

  • 实参与形参必须一一对应
  • 调用前定义函数
  • 无参数也必须保留圆括号
  • 形式参数无需声明变量类型,也不需要指定返回值类型

形参、实参

形参:

  • 在函数定义时,圆括号内自己设置的参数,只在函数执行过程中生效,其余时间失效
  • 属于函数,无法被外部调用
  • 值需要在调用时,从外部传入

实参:

  • 在调用函数时,传递值给函数的变量
  • 可以被函数内部调用,但不建议
  • 一般只传递值

返回值详解

返回值:调用函数后,返回的值

  • 使用return 语句
  • 无需预先定义
  • 返回的变量类型、数量不受限制
  • 调用函数时需要保证有变量接收
  • 执行 return 后立马结束函数

函数底层

Python中一切皆对象:

  • 函数定义时,系统创建了对应的对象
  • 小括号代表调用
  • 变量名存在堆里,也叫做函数标识符,函数的ID、值和类型也即函数对象在堆里
  • 函数可以作为参数传递,高阶函数的用法
  • 函数被调用时,会生成栈帧,stack frame,这里面存放局部变量。

变量的作用域

全局变量:

  • 在函数和类定义之外声明的变量

局部变量:

  • 函数里定义的变量
  • 函数执行完即消失
  • 局部变量与全局变量同名时,优先使用局部变量,使用全局变量前声明 global variable
  • 局部变量的引用比全局变量快,优先考虑使用

参数的传递

传递可变对象:

  • Python中一切皆对象,因此参数的传递都是对象地址的传递
  • 可变实参跟形参对应一个对象时,对形参更改后,不创建对象拷贝,直接修改这个对象,因而原本的可变实参也发生对应的变化

传递不可变对象:

  • 字符串、数字、元组都是不可变对象
  • 传参数时同样是传入对象的地址
  • 但因实参不可变,因此在对形参更改时,创建实参的拷贝并执行更改操作

浅拷贝和深拷贝

浅拷贝:

  • 不拷贝子对象的内容,只是拷贝子对象的引用
  • 拷贝了栈里的变量标识符,并且拷贝了该变量指向的堆里的对象的地址,因此作出的部分更改会
  • copy.copy()
  • 只拷贝引用
https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d1bcd336-f9e5-4359-a0dc-50fbaa779e37/Untitled.png

深拷贝:

  • 会连子对象的内容也全部拷贝一份,对子对象的修改不会影响源对象
  • 拷贝了栈里的变量标识符,拷贝了该变量指向的堆里的对象,并且拷贝了堆里对象所指向的所有子对象
  • copy.deepcopy()
  • 全部拷贝到新的内存变量
https://s3-us-west-2.amazonaws.com/secure.notion-static.com/cd2f3520-cca4-4847-8494-0eb6c06f7117/Untitled.png

不可变对象包含可变对象

参数的传递:

  • 传递不可变对象时为浅拷贝
  • 因此当不可变对象中包含可变对象时,对可变对象部分的修改会影响源数据

参数的类型

  • 位置参数:根据位置、个数跟参数匹配
  • 默认值参数:如果传入参数不足时默认参数使用默认值,默认参数必须放在最后
  • 命名参数:在调用函数传参的时候,加上参数的名称,直接赋值
  • 可变参数:定义函数时,传入参数可以为可变对象
https://s3-us-west-2.amazonaws.com/secure.notion-static.com/3cdd9db3-97e3-48e9-8168-6d2b66768f7e/Untitled.png
  • 强制命名参数:带星号的'可变参数'后面增加新的参数,必须是 '强制命名参数'
https://s3-us-west-2.amazonaws.com/secure.notion-static.com/32c2e91b-6bb2-4ad8-9d74-e2c005959f85/Untitled.png

lambda 表达式和匿名函数

lambda para1, para2, para3, ...:

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d2709ea5-1ae2-4962-89c5-3ea71e4d045b/Untitled.png

eval 函数

用法如下:

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/b09f1925-adff-47ca-9a56-cfd0ca2eff32/Untitled.png

很有意思的函数,可以用于动态更新代码

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/177f94d3-9407-4610-9dd4-deb8068d6446/Untitled.png

递归函数

就是自己调用自己罢了,套娃,但是记得加上终止条件,一般都是迭代条件。

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/f12abfaa-fd76-4c53-b19b-7cb4f85eebfa/Untitled.png

类对象

使用 "class 类名:",实际上,当解释器执行 class 语句时,就会创建一个类对象。

  • 新建的类是type下面的一个模板
https://s3-us-west-2.amazonaws.com/secure.notion-static.com/3f4df708-b3de-4bfa-a063-ae17a06bc9db/Untitled.png
  • 类对象贼有意思
https://s3-us-west-2.amazonaws.com/secure.notion-static.com/6c0c6427-e7c4-4d30-9143-77bf5d0c87b4/Untitled.png

嵌套函数

  • 设置内置嵌套函数可以降低内部重复代码
  • 很有意思
https://s3-us-west-2.amazonaws.com/secure.notion-static.com/21a1533f-fd5c-4178-a008-2111cdc1e56a/Untitled.png

nonlocal global

  • nonlocal 声明外层的局部变量
  • global 声明全局变量

LEGB 规则

Python在查找一个名字时,按照该顺序查找:

  • Local - Enclosed - Global - Built in
  • 局部变量 - 闭包 - 全局变量 - Python保留字
赞赏