python入门(8)变量进阶、函数的参数和返回值、递归

一、变量的引用

变量和数据都是保存在内存中的,在python中函数的参数传递以及返回值都是靠引用传递的

  • 引用的概念
    变量和数据是分开存储的,
    数据保存在内存中的一个位置,
    变量中保存着数据在内存中的地址,
    变量中记录数据的地址,就叫做引用
    使用id()函数可以查看变量中保存数据所在的内存地址
    **注意:**如果变量已经被定义,当给一个变量赋值的时候,本质上是修改了数据的引用,变量不再对之前的数据引用,变量改为对新赋值的数据引用

在这里插入图片描述
案例代码:

def test(num):
    print("在函数内部 %d 对应的内存地址是 %d" % (num,id(num)))

    #1> 定义一个字符串变量
    result = "hello"
    print("函数要返回数据 hello 的内存地址是 %d " % id(result))
    #2> 将字符串变量返回,返回的是数据的引用,而不是数据本身
    return result
# 1. 定义一个数字的变量
a = 10
# 数据的地址本质上就是一个数字
print("a 变量值为 10 保存数据的内存地址是 %d " % id(a))

# 2.调用test函数,本质上传递的是实参保存数据的引用,而不是实参保存的数据本身
# 注意:如果函数有返回值,但是没有定义变量接收
# 程序不会报错,但是无法获得返回结果
r = test(a)
print("%s 的内存地址是 %d " % (r,id(r)))

运行结果:
在这里插入图片描述

二、可变和不可变类型

  • 不可变类型
    内存中的数据不允许被修改
    数字类型:int ,bool,float,complex,long(2,x)
    字符串:str
    元组tuple
  • 可变类型
    内存中的数据可以被修改
    列表list
    字典dict
  • 注意
    字典中的key只能使用不可变类型的数据
    可变类型的数据变化是通过方法来实现的
    如果给一个可变类型的变量赋值了一个新的数据,引用会修改,变量不再对之前的数据引用,变量改为对新赋值的数据引用
  • hash(哈希)
    python中内置有一个名字叫做hash(o)的函数,接收一个不可变类型的数据作为参数,返回结果是一个整数。
    哈希是一种算法,其作用就是提取数据的特征码,相同的内容得到相同的结果,不同的内容得到不同的结果。
    在python中,设置字典的键值对时,会首先对key进行hash以决定如何在内存中保存字典的数据,以方便后续对字典的操作:增删查改;键值对的key必须是不可变类型的数据,键值对的value可以是任意类型的数据。

三、局部变量和全局变量

局部变量:在函数内部定义的变量,只能在函数内部使用
全局变量:在函数外部定义的变量(没有定义在某一个函数内),所有函数内部都可以使用这个变量。
提示:在其他开发语言中,大多不推荐使用全局变量—可变范围太大,导致程序不好维护!

1.局部变量

  • 局部变量是在函数内部定义的变量,只能在函数内部使用;
  • 函数执行结束后,函数内部的局部变量,会被系统回收;
  • 不同的函数,可以定义相同的名字的局部变量,但是各用各的不会产生影响
  • 局部变量的作用:在函数内部使用,临时保存函数内部需要使用的数据
  • 局部变量案例
def demo1():
    #定义一个局部变量
    num = 10
    print("在demo1函数内部的变量是 %d" % num)

#在函数内部定义的变量,不能在其他位置使用
demo1()
  • 局部变量的生命周期
    生命周期:是变量从被创建到系统回收的过程
    局部变量在函数执行时才会被创建,函数执行结束后局部变量被系统回收
    局部变量在生命周期内,可以用来存储函数内部临时使用到的数据

2.全局变量

  • 全局变量是在函数外部定义的变量,所有的函数内部都可以使用这个变量

  • 注意:函数执行时,需要处理变量时会:
    首先查找函数内部是否存在指定名称的局部变量,如果有,直接使用
    如果没有,查找函数外部是否存在指定名称的全局变量,如果有,直接使用
    如果还没有,程序报错!

num = 10
def demo1():
    print("demo1 ===》 %d" % num)

def demo2():
    print("demo2 ===》 %d" % num)

demo1()
demo2()
  • 函数不能直接修改全局变量的引用
    全局变量是在函数外部定义的变量(没有定义在某一个函数内),所有函数内部都可以使用这个变量。
    在函数内部,可以通过全局变量的引用获取到对应的数据
    但是,不允许直接修改全局变量的引用—使用赋值语句修改全局变量的值
num = 10
def demo1():
    #在python中,是不允许直接修改全局变量的值
    #如果使用赋值语句,会在函数内部,定义一个局部变量
    num = 99
    print("demo1 ===》 %d" % num)

def demo2():
    print("demo2 ===》 %d" % num)

demo1()
demo2()

运行截图:
在这里插入图片描述

  • 在函数内部修改全局变量的值
    如果在函数中需要修改全局变量,需要使用global进行声明
num = 10
def demo1():
    #希望修改全局变量的值 -- 使用global声明一下变量即可
    #global 关键字会告诉解释器后面的变量是一个全局变量
    #再使用赋值语句时,就不会创建局部变量
    global num
    num = 99
    print("demo1 ===》 %d" % num)

def demo2():
    print("demo2 ===》 %d" % num)

demo1()
demo2()

运行截图:
在这里插入图片描述

  • 全局变量定义的位置
    在开发时,应该把模块中的全局变量都定义在所有函数的上方,就可以保证所有的函数,都能够正常的访问到每一个全局变量了。
    shebang标识用哪个解释器解释当前的代码
    在这里插入图片描述
  • 全局变量命名的建议
    为了避免局部变量和全局变量出现混淆,在定义全局变量时,有些公司会有一些开发要求,例如:全局变量名前应该增加g_或者gl_的前缀
gl_num = 10
def demo():
    #如果局部变量的名字和全局变量的名字相同
    #pycharm会在局部变量下方显示一个灰色的虚线
    num = 99
    print("demo1 ===》 %d" % num)
    print("全局变量 ===》 %d" % gl_num)
demo()

运行截图:
在这里插入图片描述

四、函数参数和返回值的作用

  • 如果函数内部处理的数据不确定,就可以将外界的数据以参数传递到函数内部
  • 如果希望一个函数执行完毕后,向外界汇报执行结果,就可以增加函数的返回值

在这里插入图片描述

五、函数的返回值

  • 函数执行结束后,告诉调用者一个结果,以便调用者针对具体的结果做后续的处理。
  • 返回值是函数完成工作后,最后给调用者的一个结果
  • 在函数中使用return关键字可以返回结果
  • 调用函数一方可以使用变量来接收函数的返回结果
  • 案例:使用元组同时返回多个变量,温度和湿度测量,同时返回温度和湿度
    元组-可以包含多个数据,因此可以使用元组让函数一次返回多个值
    如果函数返回的类型是元组,小括号可以省略
def measure():
    """测量温度和湿度"""
    print("测量开始。。。")
    temp = 39
    wetness = 50
    print("测量结束。。。")
    # 元组-可以包含多个数据,因此可以使用元组让函数一次返回多个值
    # 如果函数返回的类型是元组,小括号可以省略
    return temp, wetness


result = measure()
print(result)
  • 接收返回元组函数的方式
    如果函数返回的类型是元组,同时希望单独的处理元组中的元素,可以使用多个变量,一次接收函数的返回结果,注意:使用多个变量接收结果时,变量的个数应该和元组中元素的个数保持一致。
def measure():
    """测量温度和湿度"""
    print("测量开始。。。")
    temp = 39
    wetness = 50
    print("测量结束。。。")
    # 元组-可以包含多个数据,因此可以使用元组让函数一次返回多个值
    # 如果函数返回的类型是元组,小括号可以省略
    return temp, wetness


gl_temp,gl_wetness = measure()
print(gl_temp)
print(gl_wetness)
  • 交换数字
    解法1–使用其他变量
a = 6
b = 100

#解法1--使用其他变量
c = a
a = b
b = c

print(a)
print(b)

解法2–不使用其他变量

a = 6
b = 100

# 解法2--不使用其他变量
a = a + b
b = a - b
a = a - b
print(a)
print(b)

解法3 --python专有

a = 6
b = 100

# 解法3 --python专有
# 等号右边是一个元组,只是括号省略了
a,b = b,a
print(a)
print(b)

六、函数的参数

  • 无论传递的参数是可变还是不可变的,只要针对参数使用赋值语句,会在函数内部修改局部变量的引用,不会影响到外部变量的引用
def demo(num,num_list):
    print("函数内部的代码")
    #在函数内部,针对参数使用赋值语句,不会修改到外部的实参变量
    num = 100
    num_list = [1,2,3]
    print("num = %d " % num)
    print(num_list)
    print("函数执行完成")

gl_num = 99
gl_num_list = [4,5,6]
demo(gl_num,gl_num_list)
print("gl_num = %d " % gl_num)
print(gl_num_list)

运行截图:
在这里插入图片描述

  • 如果传递的参数是可变类型,在函数内部,使用方法修改了数据的内容,同样会影响到外部的数据。
def demo(num_list):
    print("函数内部的代码")
    # 使用方法修改列表的内容
    num_list.append(9)
    print(num_list)
    print("函数执行完成")

gl_list = [4,5,6]
print(gl_list)
demo(gl_list)
print(gl_list)

运行截图:
在这里插入图片描述

  • +=
    在python中,列表变量调用+=本质上是在执行列表变量的extend方法,不会修改变量的引用。
def demo(num,num_list):
    print("函数开始")
    # 使用方法修改列表的内容
    num += num
    # 列表变量使用 += 不会做相加再赋值的操作,本质上是在调用列表的extend方法
    #     num_list = num_list + num_list  等式不等于  num_list += num_list
    num_list += num_list
    print(num)
    print(num_list)
    print("函数完成")


gl_num = 9
gl_list = [4,5,6]
demo(gl_num,gl_list)
print(gl_num)
print(gl_list)

运行截图:
在这里插入图片描述

七、缺省参数

  • 定义函数时,可以给某个参数指定一个默认值,具有默认值的参数就叫做缺省参数
  • 调用函数时,如果没有传入缺省参数的值,则在函数内部使用定义函数时指定的参数默认值
  • 函数的缺省参数,将常见的值设置为参数的缺省值,从而简化函数的调用
  • 例如,对列表排序的方法
gl_list = [4,2,7]

# 默认按照升序排序
gl_list.sort()
print(gl_list)

# 如果需要降序排序,需要执行reverse参数
gl_list.sort(reverse=True)
print(gl_list)

运行截图:
在这里插入图片描述

  • 指定函数的缺省参数
    在参数后使用赋值语句,可以指定参数的缺省值。
    提示:缺省参数,需要使用最常见的值作为默认值!如果一个参数的值不能确定,则不应该设置默认值,具体的数值在调用函数时,由外界传递。
def print_info(name,gender=True):
    """

    :param name: 班上同学的姓名
    :param gender: True 男生  False 女生
    """
    gender_text = "男生"
    if not gender:
        gender_text = "女生"
    print("%s 是 %s " % (name,gender_text))
 
# 假如班上的同学,男生居多 
# 提示:在指定缺省参数的默认值时,应该使用最常见的值作为默认值!
print_info("小明")
print_info("小王")
print_info("小美",False)
  • 缺省参数的注意事项
    缺省参数的定义位置:必须保证带有默认值的缺省参数在参数列表末尾
    错误案例:def print_info(name,gender=True,title)
    调用带有多个缺省参数的函数,在调用函数时,如果有多个缺省参数,需要指定参数名,这样解释器才能够知道参数的对应关系。
def print_info(name,gender=True):
    """

    :param name: 班上同学的姓名
    :param gender: True 男生  False 女生
    """
    gender_text = "男生"
    if not gender:
        gender_text = "女生"
    print("%s 是 %s " % (name,gender_text))
 
# 假如班上的同学,男生居多 
# 提示:在指定缺省参数的默认值时,应该使用最常见的值作为默认值!
print_info("小明")
print_info("小王")
print_info("小美",False)

运行截图:
在这里插入图片描述

八、多值参数

1.定义支持多值参数的函数

  • 有时可能需要一个函数能够处理的参数个数是不确定的,这个时候,就可以使用多值参数
  • python中有两种多值参数:参数名前增加一个*可以接收元组,参数名前增加两个*可以接收字典
  • 一般在给多值参数命名时,习惯使用以下两个名字;
    *args----存放元组参数,前面有一个*,args是arguments的缩写,有变量的含义
    **kwargs —存放字典参数,前面有两个*,kw是keyword的缩写,kwargs可以记忆键值对参数
def demo(num,*nums,**person):
    print(num)
    print(nums)
    print(person)

demo(1,2,3,name = "小明",age = 18)

运行截图:
在这里插入图片描述

2.多值参数案例–计算任意多个数字的和

需求:定义一个函数sum_numbers,可接收任意多个整数,功能要求:将传递的所有数字累加并且返回累加结果
代码:

def sum_numbers(*args):
    num = 0
    print(args)
    #循环遍历
    for n in  args:
        num += n
    return  num
result = sum_numbers(1,2,3,4,5)
print(result)

运行截图:
在这里插入图片描述

3.元组和字典的拆包

在调用带有多值参数的函数时,如果希望将一个元组变量,直接传递给args,将一个字典变量,直接传递给kwargs,就可以使用拆包,简化参数的传递,
拆包的方式是:在元组变量前,增加一个*,在字典变量前,增加两个*

def demo(*args,**kwargs):
    print(args)
    print(kwargs)

# 元组变量、字典变量
gl_list = (1,2,3)
gl_dict = {"name":"小明","age":18}
demo(*gl_dict,**gl_dict)

运行截图:

在这里插入图片描述

九、递归

函数调用自身的编程技巧称为递归

1.递归函数的特点

一个函数内部调用自己,函数内部可以调用其他函数,当然在函数内部也可以调用自己

  • 代码特点
    函数内部的代码是相同的,只是针对参数不同,处理的结果不同
    当参数满足一个条件时,函数不再执行(这个非常重要通常被称为递归的出口,否则会出现死循环)
  • 案例介绍:使用递归打印3,2,1
def sum_sumbers(num):
    print(num)
    #递归的出口,当参数满足某个条件时,不再执行函数
    if num == 1:
        return
    #自己调用自己
    sum_sumbers(num - 1)

sum_sumbers(3)

运行截图:
在这里插入图片描述
代码执行流程图:
在这里插入图片描述

  • 递归案例–计算数字累加
    需求:定义一个函数sum_numbers,能够接收一个num的整数参数,计算1+2+3+。。num的结果
def sum_sumbers(num):
    # 1.出口
    if num == 1:
        return 1
    # 2.数字的累加num+(1...num-1)
    temp = sum_sumbers(num - 1)
    #两个数字的相加
    return num + temp

result = sum_sumbers(10)
print(result)

累加运行流程图:
在这里插入图片描述
提示:递归是一个编程技巧,初次接触递归会感觉有些吃力,在处理不确定的循环条件时,格外的有用,例如遍历整个文件目录的结构。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值