跳转至

再学函数

局部变量和全局变量

请大家运行如下代码

var = '桌子'

def test():
    var = '椅子'
    print(f"在函数中,var的值是:{var}")


test()
print(f"在函数外,var的值是:{var}")

这段代码中,函数里面和函数外面都定义了一个名字为var 的变量。

在函数里面和函数外面都执行打印语句,输出 var 变量的值

运行一下,就会发现输入如下结果

在函数中,var的值是:椅子
在函数外,var的值是:桌子

在函数外面定义的变量称之为 全局(global)变量

在函数里面定义的变量称之为 局部(local)变量

如果在函数内部有 变量赋值语句,且该变量名和全局变量相同,会产生一个新的局部变量,而不是将全局变量进行重新赋值。

同名的局部变量和全局变量,虽然它们两个名字相同,但其实它们是不同的变量,指向不同的对象。

刚才的运行结果说明了:如果全局变量和局部变量同名,函数体里面的代码使用的是局部变量。


如果不是赋值语句,函数里面可以直接使用外部的全局变量,比如

var = '桌子'

def test():
    print(f"在函数中,var的值是:{var}")

test()

运行结果是

在函数中,var的值是:桌子


那么如果我们就是需要在函数内部 把全局变量进行重新赋值,该怎么办呢?

这时,就需要我们在函数内部使用 global 关键字声明,使用的是全局变量。

比如

var = '桌子'

def test():
    global  var
    var = '椅子'
    print(f"在函数中,var的值是:{var}")

test()
print(f"在函数外,var的值是:{var}")

调用test函数的时候, 由于 global var 声明了:在函数内部的变量var就是全局变量var,所以下面的这条语句就改变了 全局变量var的值

var = '椅子'

在函数调用结束后, 全局变量var的值产生了相应的改变。

所以运行结果如下:

在函数中,var的值是:椅子
在函数外,var的值是:椅子


可变参数

假设我们有这样的一个字典,存储学生年龄,如下:

studentInfo = {
    '张飞' :  18,
    '赵云' :  17,
    '许褚' :  16,
    '典韦' :  18,
    '关羽' :  19,
}

要实现一个函数 printAge ,它的输入参数是一些学生的姓名,函数需要打印出这些输入学生的年龄。

这里有个问题,就是调用printAge 时, 输入的学生名字 个数是不固定的,可能是1个、2个、100个, 甚至也可能是0个。

这肯定难不倒聪明的你, 你一番思考,决定使用列表作为参数类型, 列表里面每个元素存放要获取年龄信息的学生名。

像这样

studentInfo = {
    '张飞' :  18,
    '赵云' :  17,
    '许褚' :  16,
    '典韦' :  18,
    '关羽' :  19,
}

def  printAge(students) :
    for  student in students:
        print( f'学生:{student} , 年龄 {studentInfo[student]}')

printAge(['张飞', '典韦', '关羽'])
printAge(['赵云'])

运行一下看看, 完全没有问题。

但是我们似乎觉得,如果调用该函数的时候,能把下面这种写法

printAge(['张飞', '典韦', '关羽'])

改为

printAge('张飞', '典韦', '关羽')

这样调用。 显得更加易读易懂。

但是问题就在于,因为这个函数参数的个数是不确定的,函数如何定义呢?

Python中可以这样定义

def  printAge(*students) :
    for  student in students:
        print( f'学生:{student} , 年龄 {studentInfo[student]}')

和上面相比,唯一的改动就是, 参数名前面加了一个星号。

然后我们就可以这样调用该函数了

printAge('张飞', '典韦', '关羽')
printAge('赵云')

效果和前面一种定义完全一样。

这种前面加一个星号的参数,称之为可变参数,

在调用该函数的时候,Python解释器会创建一个 tuple 赋值给这个参数变量。并且会把 传入的数据对象 放到这个tuple对象里面。

也就是说,上面的例子里面,如下调用代码执行的时候,

printAge('张飞', '典韦', '关羽')
Python解释器创建一个 tuple 赋值给这个 students,里面存放了 '张飞', '典韦', '关羽' 三个字符串对象作为元素,

我们在代码里加入一行语句,显示 students 类型

studentInfo = {
    '张飞' :  18,
    '赵云' :  17,
    '许褚' :  16,
    '典韦' :  18,
    '关羽' :  19,
}

def  printAge(*students) :
    print(type(students))
    for  student in students:
        print( f'学生:{student} , 年龄 {studentInfo[student]}')

printAge('张飞', '典韦', '关羽')

运行结果显示

<class 'tuple'>
学生:张飞 , 年龄 18
学生:典韦 , 年龄 18
学生:关羽 , 年龄 19

说明 students变量确实是对应一个tuple对象。


printAge 使用上面这样的可变参数,假如我们要传入的参数恰好已经在一个list(或者tuple) 中,比如

onebatch = ['张飞', '典韦', '关羽']

怎么调用printAge呢?

当然可以这样

printAge (onebatch[0], onebatch[1], onebatch[2])

显然不方便。

其实,我们可以这样

printAge(*onebatch)

在调用时,这就是参数展开。

我们可以将其等价于

printAge (onebatch[0], onebatch[1], onebatch[2])

大家注意,这里是在调用函数的时候,传入参数前面加上星号,是参数展开;

前面我们讲的可变参数是在函数定义的时候前面加上星号。

大家不要搞混了。

关键字可变参数

参数个数不确定,除了上面这种定义的方式,还有另外一种定义方式,叫做关键字可变参数

比如,我们要实现一个函数,可以在 学生年龄表里面添加新的学生信息, 可以输入不定数量的学生信息,包括姓名和年龄。

可以这样定义

def addStudents(table,**students):
    print(type(students))
    for name,age in students.items():
        table[name] = age

table1 = {}
table2 = {}
addStudents(table1, 李白=20, 杜甫=24)
addStudents(table2, Jodan=45, James=32, onil=40)
print(table1)
print('----------------')
print(table2)

运行一下,输出结果如下

<class 'dict'>
<class 'dict'>
{'李白': 20, '杜甫': 24}
----------------
{'Jodan': 45, 'James': 32, 'onil': 40}

其中 <class 'dict'> 说明了 前面有两个星号 的 参数变量 students 的值是一个字典。

这种前面加2个星号的参数,称之为关键字可变参数,

在调用该函数的时候,Python解释器会创建一个 dict (字典) 赋值给这个参数变量。

并且会把 传入的数据对象 分别放到这个dict 对象里面。

传入的参数对象,必须是像 name=value这种 带参数名和参数值的, 放到dict对象时,参数名是字典元素的key,参数值是字典元素的value。

也就是说,上面的例子里面,如下调用代码执行的时候,

addStudents(table1, 李白=20, 杜甫=24)
Python解释器创建一个 字典 赋值给参数变量 students,把 李白,20杜甫,24 作为 2个键值对元素放到 该字典中。


addStudents 使用上面这样的关键字可变参数,假如我们要传入的参数恰好已经在一个字典 中,比如

onebatch = {'李白': 20, '杜甫': 24}

怎么调用addStudents呢?

可以这样参数展开

onebatch = {'李白': 20, '杜甫': 24}
addStudents(table1, **onebatch)

和上面不同的是,对字典,要使用两个星号进行参数展开,Python解释器会把字典里面,每个元素的键作为参数名,值作为参数值,这样进行函数调用

您需要高效学习,找工作? 点击咨询 报名实战班

点击查看学员就业情况

课后练习

去做练习