这一节有点难。看不懂没关系。继续往后学,回头再来看。

10.6 函数参数传递的机制

10.6.1 值传递与引用传递

编程语言的参数传递机制通常有两种:

  • 值传递

    • 拷贝参数的值,然后传递给函数里的新变量。这样,原变量和新变量之间互相独立,互不影响。

  • 引用传递

    • 把参数的引用传给新的变量,这样,原变量和新变量就会指向同一块内存地址。如果改变了其中任何一个变量的值,那么另外一个变量也会相应地随之改变。

10.6.2 Python 参数传递是赋值传递

这里首先引用 Python 官方文档中的一段说明:

“Remember that arguments are passed by assignment in Python. Since assignment just creates references to objects, there’s no alias between an argument name in the caller and callee, and so no call-by-reference per Se.”

准确地说,Python 的参数传递是赋值传递 (pass by assignment),或者叫作对象的引用传递(pass by object reference)。Python 里所有的数据类型都是对象,所以参数传递时,只是让新变量与原变量指向相同的对象而已,并不存在值传递或是引用传递一说。不要与引用传递弄混了,引用传递的是一个地址。

  • 不可变对象作为参数

def my_func1(b):  b = 2  #③函数执行时,变量b指向对象2a = 1  # ①实参变量a指向对象1my_func1(a)  #②因为是赋值传递,变量 b 也指向了变量a指向的对象 1 a  # ④函数执行完成后,变量a依然指向对象11

代码中注释里面的序号是程序的执行顺序。函数被调用时(②),因为是赋值传递,所以函数形参变量b指向了 实参变量 a  所指向的对象1。但当代码执行到 b = 2 时(③),系统会重新创建一个值为 2 的新对象,并让 b 指向它;而 a 仍然指向 1 这个对象。所以,a 的值不变,仍然为 1。

稍作改变,让函数返回新变量,赋给 a,再来看看。

def my_func2(b):  b = 2  #③函数执行时,变量b指向对象2  return b  # ④关键,函数返回一个指向对象2的变量a = 1 # ①实参变量a指向对象1a = my_func2(a)  # ②将my_func返回值(指向对象2)赋值给了a,所以a 也指向了对象2a2
  • 可变对象作为参数

当可变对象当作参数传入函数里的时候,改变可变对象的值,就会影响所有指向它的变量。

def my_func3(l2):    l2.append(4)  # ③在原对象[1,2,3]上修改,对象变为 [1,2,3,4]l1 = [1, 2, 3] # ① l1是个可变对象,指向了对象[1,2,3]my_func3(l1) #②因为是赋值传递,变量 l2 也指向了变量l1指向的对象 [1,2,3]l1  # ④函数执行完成后,l1和l2指向的对象发生了改变[1, 2, 3, 4]

如果多次调用my_func3,那么每次l1得到的结果都不一样,l1不断在列表后面添加元素4。

def my_func3(l2):    l2.append(4)  # ③在原对象[1,2,3]上修改,对象变为 [1,2,3,4]if __name__ == '__main__':    l1 = [1, 2, 3] # ① l1是个可变对象,指向了对象[1,2,3]    my_func3(l1) #②因为是赋值传递,变量 l2 也指向了变量l1指向的对象 [1,2,3,4]    print(l1)    my_func3(l1)  # ②因为是赋值传递,变量 l2 也指向了变量l1指向的对象 [1,2,3,4,4]    print(l1)    my_func3(l1)  # ②因为是赋值传递,变量 l2 也指向了变量l1指向的对象 [1,2,3,4,4,4]    print(l1)

不改变原来可变对象的值,而是生成新对象,结果与上面不同。看下下面的:

def my_func4(l2):    l2 = l2 + [4]  # 创建了一个“末尾加入元素 4“的新对象,原对象没变l1 = [1, 2, 3]my_func4(l1)l1[1, 2, 3]  # l1对象没变

实际工程中,我们一般不希望函数内部可以修改外部变量的值,因为可能会导致代码出现异常而且难以排查问题所在。所以通常函数内部重新创建一个新的列表(可变对象),对这个新列表(可变对象)进行操作,而不是操作输入的列表,并增加语句return 语句。再来看一个类似的例子:

def multiply_2_pure(l):    new_list = []  # 创建一个新列表    for item in l:        new_list.append(item * 2)    return new_list  # 返回新列表

10.7 函数变量作用域

10.7.1 局部变量

定义在函数内部,它的作用域是在函数内部,函数调用结束之后,函数里面保存的信息就被销毁了。比如下面的这个代码示例,连续调用函数4次,每次输出的值都是4,即3+1,这说明每次调用fun函数之后,函数内部定义的局部变量num就被销毁了,再次被调用时将被重新初始化为1,那如果要保存函数的局部变量,怎么办呢?后面介绍的“闭包”就可以完成这个任务。

def fun(step):    num = 1    num += step    print(num)i = 1while i < 5:    fun(3)    i += 1

10.7.2 全局变量

定义在整个文件层次上,如下MIN_VALUE和MAX_VALUE这两个变量就是全局变量,通常大写。

MIN_VALUE = 1MAX_VALUE = 10def validation_check(value):    if value < MIN_VALUE or value > MAX_VALUE:        raise Exception('validation check fails')

不能在函数内部随意改变全局变量的值,一定要改变的话,要在全局变量前面加个global。global的作用就是在“函数局部作用域”内声明表示一个全局变量,从而可以在函数内部修改全局变量的值(否则只能访问不能修改)。

MIN_VALUE = 1MAX_VALUE = 10def validation_check(value):    global MIN_VALUE  # 表示函数内部的这个MIN_VALUE是来自全局变量MIN_VALUE    MIN_VALUE += 1  print(MIN_VALUE) validation_check(5)  # 输出2

10.7.3 局部变量覆盖全局变量

如果遇到函数内部局部变量和全局变量同名的情况,那么在函数内部,局部变量会覆盖全局变量。

MIN_VALUE = 1MAX_VALUE = 10def validation_check(value):    MIN_VALUE = 3    print(MIN_VALUE) # 输出3validation_check(5)

10.8 函数的嵌套

函数可以嵌套定义。

  • 形式1,在函数内部直接调用定义的内部函数

def outer(name):    num = 100    def inner(weight, height, age):        weight += 1        height += 1        age += 1        print(name, weight, height, age)    inner(100, 200, 300)  # 直接调用“内部函数”outer('盒子')
  • 形式2,在函数内部return定义的内部函数

def outer(name):    num = 100    def inner(weight, height, age):        weight += 1        height += 1        age += 1        print(name, weight, height, age)    return inner  # 返回函数对象alias = outer('盒子')  # 调用外部函数,得到inner对象alias(100, 200, 300)  # 调用inner函数对象,传入三个参数
  • 闭包,外部函数执行完后,外部函数的参数仍然会被内部函数记住。

def nth_power(exponent):  # 外部函数    def exponent_of(base):        return base ** exponent  # 内部函数使用了外部函数的参数    return exponent_of  # 外部函数返回内部函数exponent_ofsquare = nth_power(2)  # exponent_of赋值给变量square,square记住了外部函数的exponent参数值2cube = nth_power(3)  # exponent_of赋值给变量cube,记住了外部函数的exponent参数值3print(square(9))  # 计算9的平方print(cube(9))  # 计算9的立方

nth_power(2)被调用时,exponent被赋值为2,并且保存到exponent_of函数对象中。当square(9)被调用时,其实就是调用exponent_of函数,这个函数内部base是9,exponent是2,因此square(9)的返回值是81。

通过Pycharm的Debug功能来看一下:

从这里可以看出,代码执行到print(square(9))这一行时,nth_power(2)已经执行结束了,但是它的局部变量exponent的信息却被保存了下来,从调试窗口可以看到它的值是2,从而当进入内部函数exponent_of时,就能够计算9**2了,这就是“闭包”的最大的作用——保存局部信息不被销毁。

函数特点总结:

  • 函数也是对象

  • 函数对象可以赋值给变量

  • 函数对象可以作为参数传递给另外的函数

  • 函数对象可以作为另外一个函数的返回值

  • 函数可以嵌套定义

append函数_连载|想用Python做自动化测试?函数的参数传递机制及变量作用域相关推荐

  1. python 递归函数_连载|想用Python做自动化测试?递归函数

    " 递归函数就是函数内部调用自身,可以使代码逻辑更加易懂.但是递归也有坑,需要避免." 13.1 概念 在函数内部,可以调用其他函数.如果一个函数在内部调用自身,这个函数就是递归函 ...

  2. c++ 随机字符串_连载|想用Python做自动化测试?了解数值计算和随机数生成神器...

    " 本文掌握Python中的几种数值类型,以及算术运算.位运算.数值转换,再学习一个测试中常用来产生随机数的模块." 构建测试知识体系,欢迎关注 Python支持的数值类型有整型i ...

  3. python decimal_连载|想用Python做自动化测试?了解数值计算和随机数生成神器

    " 本文掌握Python中的几种数值类型,以及算术运算.位运算.数值转换,再学习一个测试中常用来产生随机数的模块." 构建测试知识体系,欢迎关注 Python支持的数值类型有整型i ...

  4. python初学者必背函数_新手必看python vlog 1: 函数

    关注本慕没烦恼,python新手瞧一瞧. 从今天开始,本慕开始为新手们带来福利啦!!祝各位python新手们事业有成!!? 今天,我们从最基础的开始讲. 首先大家安装PyCharm了吧!!解释器安装好 ...

  5. python怎么输入分数_我想在python中的函数中输入一个分数

    您可以使用input()内置来提示用户输入值.在python2.x上,使用raw_input().在 不必打印结果,只需返回即可.在def simp_frac(num,den): smallest = ...

  6. 想用Python做自动化测试?Python反射机制的应用

    通常,我们操作对象的属性或者方法时,是通过点"."操作符进行的.例如下面的代码: class Person:type = "mammal"def __init_ ...

  7. python done函数_【转】Python内置函数(47)——open

    英文文档: open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, ope ...

  8. 如何用 Python 做自动化测试

    本文来自作者 Vant 在 GitChat 上分享 「如何用 Python 做自动化测试」 编辑 | 哈比 一.Selenium 环境部署 1. window 环境部署 1.1 当前环境 Win10 ...

  9. python在匿名函数作和_跟光磊学Python开发-匿名函数函数和高阶函数

    跟光磊学Python开发-匿名函数函数和高阶函数 跟光磊学Python开发-匿名函数函数和高阶函数跟光磊学Python开发 匿名函数 匿名函数就是函数定义时没有名字的函数,也称为匿名表达式. 普通函数 ...

最新文章

  1. TinyBERT搜索: 比BERT快10倍,小20倍
  2. Qt pro使用sql之类的需要添加的模块
  3. Hyperledger Fabric 1.2 --- Chaincode Operator 解读和测试(一)
  4. Deep Learning论文笔记之(八)Deep Learning最新综述
  5. 趣链 BitXHub跨链平台 (1)技术架构
  6. Oracle学习操作(6)函数与存储过程
  7. 阿里云数据库MYSQL和自建数据库的对比(附新手领取免费的一个月云服务器)
  8. android wear评测,android wear5.1怎么样 android wear5.1更新评测
  9. libcurl库的安装和使用
  10. Qt5.7+Opencv2.4.9人脸识别(五)人脸识别
  11. linux 设置防火墙ip网段,网络防御-防火墙设置IP网段规则
  12. c语言图灵机算法,图灵机的时间化简概述(3/4)
  13. 基于Python的文字生成图片系统
  14. 寻宝游戏(DFS+动态规划)
  15. kali虚拟机-----破解wifi密码(WiFi渗透)
  16. 2016搜狗校招编程题
  17. “Outlook 中的搜索结果不正确,因为缺少MapiPH.dll” 的解决方法
  18. JAVA文件编码转换:gbk转utf-8
  19. 《Data Structures and Algorithm Analysis in C》学习与刷题笔记
  20. Android Studio使用Mob获取手机验证码

热门文章

  1. Unity 2021创建2D休闲点击器游戏视频教程
  2. Carrier frequency 和 EARFCN的关系
  3. 哈希表的分类,创建,查找 以及相关问题解决
  4. opencv 1 图像载入、显示和输出
  5. Linux性能分析命令工具汇总
  6. LeetCode 7. Reverse Integer
  7. vue路由对象($route)参数简介
  8. SPSS聚类分析:K均值聚类分析
  9. (24):(行为型模式) Visitor 访问者模式
  10. 两个有序单链表的并交差运算