目录
1.变量的引用
- 变量和数据都是保存在内存中的
- 在python中,函数的参数传递以及返回值都是靠引用传递。
1.1 引用的概念
在python中:
- 变量和数据是分开存储的
- 数据保存在内存中的一个位置
- 变量中保存着数据在内存中的地址
- 变量中记录数据的地址,就叫做引用
- 使用
id()
函数可以查看变量中保存数据所在的内存地址
注意:如果一个变量已经被定义,当给一个变量赋值的时候,本质上是修改了数据的引用,变量不再对之前的数据引用,变量改为对新赋值数据的引用
1.2 变量引用的示例
在python中,变量的名字类似于便签纸贴在数据上
1.3 函数的参数和返回值的传递
在python中,函数的实参/返回值都是靠引用来传递的。本质上传递的是实参保存数据的引用,而不是实参保存的数据
注意,如果函数有返回值,但是没有定义变量接收,程序不会报错,但是无法获得返回结果
def test(num):
print("-" * 50)
print("%d 在函数内的内存地址是 %x" % (num, id(num)))
result = 100
print("返回值 %d 在内存中的地址是 %x" % (result, id(result)))
print("-" * 50)
return result
a = 10
print("调用函数前 内存地址是 %x" % id(a))
r = test(a)
print("调用函数后 实参内存地址是 %x" % id(a))
print("调用函数后 返回值内存地址是 %x" % id(r))
2.可变和不可变类型
不可变类型,内存中的数据不允许被修改:
数字类型:int、bool、float、complex、long(2,x)
字符串:str
元组:tuple
可变类型,内存中的数据可以被修改:
列表:list <字典的key只能使用不可变类型的数据>
字典:dict
注意:字典的key只能使用不可变类型的数据
注意
1.可变类型的数据变化,是通过方法来实现的
2.如果给一个可变类型的变量,赋值了一个新的数据,引用会修改
变量不再对之前的数据引用
变量改为对新赋值的数据引用
3.哈希(hash)
1.Python中内置有一个名字为 hash(o) 的函数:
接收一个不可变类型的数据作为参数
返回结果是一个整数
2.哈希是一种算法,其作用是提取数据的特征码(指纹)
相同的内容,得到相同的结果;不同的内容,得到不同的结果
3.在设置字典的键值对时,会首先对key进行hash 以决定如何在内存中保存字典的数据,方便后续对字典的操作。
键值对中key必须是不可变类型的数据;value可以实任意类型的数据
4.局部变量和全局变量
● 局部变量是在函数内部定义的变量,只能在函数内部使用
● 全局变量是在函数外部定义的变量(没有定义在某一个函数内),所有函数内部都可以使用这个变量
提示:在其他的开发语言中,大多不推荐使用全局变量——可变范围太大,导致程序不好维护!
1.局部变量
● 局部变量是在函数内部定义的变量,只能在函数内部使用
● 函数执行结束后,函数内部的局部变量,会被系统回收
● 不同的函数,可以定义相同的名字的局部变量,但是各用个的不会产生影响
2.局部变量的作用
● 在函数内部使用,临时保存函数内部需要使用的数据
3.局部变量的生命周期
● 所谓生命周期就是变量从被创建到被系统回收的过程
● 局部变量在函数执行时才会被创建
● 函数执行结束后局部变量被系统回收
● 局部变量在生命周期内,可以用来存储函数内部临时使用到的数据
1.全局变量
● 全局变量是在函数外部定义的变量,所有函数内部都可以使用这个变量
注意:函数执行时,需要处理变量时会:
1.首先查找函数内部是否存在指定名称的局部变量,如果有,直接使用
2.如果没有,查找函数外部是否存在指定名称的全局变量,如果有,直 接使用
3.如果还没有,程序报错!
1)函数不能直接修改全局变量的引用
● 全局变量是在函数外部定义的变量(没有定义在某一个函数内), 所有函数内部都可以使用这个变量。
提示:在其他的开发语言中,大多不推荐使用全局变量——可变范围太大, 导致程序不好维护!
● 在函数内部,可以通过全局变量的引用获取对应的数据
● 但是,不允许直接修改全局变量的引用——使用赋值语句修改全局变量的值
注意:只是在函数内部定义了一个局部变量而已,只是变量名相同 —— 在函数内部不能直接修改全局变量的值
2)在函数内部修改全局变量的值
● 如果在函数中需要修改全局变量,需要使用global进行声明
●global关键字会告诉解释器后面的变量是一个全局变量
●再使用赋值语句时,就不会创建局部变量
3)全局变量定义的位置
● 为了保证所有的函数都能够正确使用到全局变量,应该将全局变量定义在其他函数的上方
注意
● 由于全局变量 c,是在调用函数之后,才定义的,在执行函数时,变量还没有定义,所以程序会报错!
4)全局变量命名的建议
● 为了避免局部变量和全局变量出现混淆,在定义全局变量时,有些公司会有一些开发要求,例如:全局变量名前应该增加 g_ 或者gl_ 的前缀
5.函数参数和返回值的作用
函数根据有没有参数以及有没有返回值,可以相互组合,一共有4种组合形式
1.无参数,无返回值
2.无参数,有返回值
3.有参数,无返回值
4.有参数,有返回值
定义函数时,是否接收参数,或者是否返回结果,是根据实际的功能需求来决定的
1.如果函数内部处理的数据不确定,就可以将外界的数据以参数传递到函数内部
2.如果希望一个函数执行完成后,向外界汇报执行结果,就可以增加函数的返回值
1.函数的返回值
● 在程序开发中,有时候,会希望一个函数执行结束后,告诉调用者一个结果,以便调用者针对具体的结果做后续的处理
● 返回值是函数完成工作后,最后给调用者的一个结果
● 在函数中使用return关键字可以返回结果
● 调用函数一方,可以使用变量来接收函数的返回结果
示例--温度和湿度测量
假设要开发一个函数能够同时返回当前的温度和湿度
def measure():
"""测量温度和湿度"""
print(测量开始...)
temp = 39
wetness = 50
print(测量结束...)
# 元组-可以包含多个数据,因此可以使用元组让函数一次返回多个值
# 如果函数返回的类型是元组,小括号可以省略
# return (temp,wetness)
return temp,wetness
# 元组
result = measure()
print(result)
# 需要单独的处理温度或者湿度 - 不方便
print(result[0])
print(result[1])
# 如果函数返回的类型是元组,同时希望单独的处理元组中的元素
# 可以使用多个变量,一次接收函数的返回结果
# 注意:使用多个变量接收结果时,变量的个数应该和元组中元素的个数保持一致
gl_temp,gl_wetness = measure()
print(gl_temp)
print(gl_wetness)
2.面试题--交换两个数字
题目要求:
1.有两个整数变量a=6,b=100
2.不使用其他变量,交换两个变量的值
3.1 不可变和可变的参数
问题1:在函数内部,针对参数使用赋值语句,会不会影响调用函数时传递的实参变量?--不会!
●无论传递的参数是可变还是不可变,只要针对参数使用赋值语句,会在函数内部修改局部变量的引用,不会影响到外部变量的引用
问题2:如果传递的参数是可变类型,在函数内部,使用方法修改了数据的内容,同样会影响到外部的数据
面试题-- +=
在python中,列表变量调用+=本质上是在执行列表变量的extend方法,不会修改变量的引用
3.2 缺省参数
●定义函数时,可以给某个参数指定一个默认值,具有默认值的参数就叫做缺省参数
●调用函数时,如果没有传入缺省参数的值,则在函数内部使用定义函数时指定的参数默认值
●函数的缺省参数,将常见的值设置为参数的缺省值,从而简化函数的调用
●例如:对列表排序的方法
指定函数的缺省参数
●在参数后使用赋值语句,可以指定参数的缺省值
提示
1.缺省参数,需要使用最常见的值作为默认值!
2.如果一个参数的值不能确认,则不应该设置默认值,具体的数值在调用函数时,由外界传递!
缺省参数的注意事项
1)缺省参数的定义位置
●必须保证带有默认值的缺省参数在参数列表末尾
所以,以下定义是错误的!
2)调用带有多个缺省参数的函数
●在调用函数时,如果有多个缺省参数,需要指定参数名,这样解释器才能够知道参数的对应关系!
3.3 多值参数
定义支持多值参数的函数
●有时可能需要一个函数能够处理的参数个数是不确定的,这个时候,就可以使用多值函数
●python中有两种多值参数:
参数名前增加一个*可以接收元组
参数名前增加两个*可以接收字典
●一般在给多值参数命名时,习惯使用以下两个名字
*args——存放元组参数,前面有一个*
**kwargs——存放字典参数,前面有两个*
●args是arguments的缩写,有变量的含义
●kw是keyword的缩写,kwargs可以记忆键值对参数
多值参数案例——计算任意多个数字的和
需求
1.定义一个函数sum_numbers,可以接收的任意多个整数
2.功能要求:将传递的所有数字累加并且返回累加结果
元组和字典的拆包
●在调用带有多值参数的函数时,如果希望:
将一个元组变量,直接传递给args
将一个字典变量,直接传递给kwargs
●就可以使用拆包,简化参数的传递,拆包的方式是:
在元组变量前,增加一个*
在字典变量前,增加两个*
4.函数的递归
4.1 递归函数的特点
特点
●一个函数内部调用自己
函数内部可以调用其他函数,当然在函数内部也可以调用自己
代码特点
1.函数内部的代码是相同的,只是针对参数不同,处理的结果不同
2.当参数满足一个条件时,函数不再执行
●这个非常重要,通常被称为递归的出口,否则会出现死循环!
4.2 递归案例——计算数字累加
需求
1.定义一个函数sum_numbers
2.能够接收一个num的整数参数
3.计算1+2+...+num的结果