首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

每天 3 分钟,小闫带你学 Python(二十二)

正文共:4023 字 6 图 预计阅读时间:11分钟

每日分享

Often when you think you're at the end of something, you're at the beginning of something else.

常常当你觉得走到尽头时,其实是在另一旅程的起点。

前言

昨天的文章『每天 3 分钟,小闫带你学 Python(二十一)』讲解了函数的4种类型、函数的嵌套使用、拆包以及交换变量的值,遗忘的同学可以点击链接查看昨天的内容,下面开始新知识的学习吧。

学习目标

1.理解局部变量与全局变量的区别

2.了解引用(偏底层)

3.熟悉可变和不可变类型

4.了解函数使用注意事项

1.局部变量

定义:局部变量就是函数内部定义的变量

作用:为了临时保存数据需要在函数中定义变量来进行存储。

生命周期:调用函数时,局部变量被创建;调用完成后,局部变量被销毁。

生命周期就是从生到死,类比人的一生。

适用范围:局部变量所在函数内部,即只能在函数内部进行使用,在函数外部调用无效。

Tip:因为其作用范围只是在此函数内部,所以不同函数内可以定义同名的局部变量。

函数内部如果定义相同名字的变量会发生覆盖,只保存最后一次定义变量的值。假设每个人都是一个函数,我买了一部 iPhone XS 后,就不会再去买一台同样的(有些浪费)手机,即使买了两台一模一样的,我也只会使用最新的那个,旧的那个垫桌脚。 两个函数内部,可以定义相同名字变量,因为它们都是局部变量,只在自己函数内部生效。就好比我买了一台 iPhone XS,你也可以买一台一模一样的 iPhone XS,互不相关。

2.全局变量

定义:如果一个变量,既能在一个函数中使用,也能在其他的函数中使用,这样的变量就是全局变量,全局变量定义在函数外部。

作用:方便多个函数调用,减少重复变量的创建。

生命周期:执行整个程序(一个 py 文件)时创建,执行完后销毁。

局部变量的生命周期则是程序中调用一个函数的起始与结束。

适用范围:整个程序

接着上面的例子扩展,局部变量好比我们每个人的手机,可以相同,可以不同。而全局变量则是一台公共电话,我可以使用,你也可以使用。

2.1 全局变量和局部变量名字相同的问题

既然全局变量任何函数都可以访问,局部变量只是函数内部生效,那么当局部变量的名字不小心和全局变量名字相同时,会发生什么?

答:函数内部定义同名局部变量之后,会使用局部变量的值,但是并没有修改全局变量,可以理解为在函数内部定义了一个和全局变量同名的局部变量,局部变量优先级比较高而已,即先使用局部变量。看下方代码,用心理解一下:

代码语言:javascript
复制
# 定义全局变量
a = 18

# 定义函数
def testA():
    a = 31
    print('定义同名局部变量之后')
    print(a)

def testB():
    print('调用全局变量,查看是否被修改')
    print(a)

testA()
testB()

执行结果如下:

代码语言:javascript
复制
定义同名局部变量之后
31
调用全局变量,查看是否被修改
18

可以看到当函数内部定义同名局部变量之后,使用的是局部变量的值。 我在测试时候发现一个现象,当你在函数内部定义同名局部变量之后,如果没有特殊操作,这个函数内无法调用全局变量。比如你会想先调用全局变量,然后再定义局部变量,这样会先输出全局变量,再输出局部变量。但是当你先调用了全局变量,再定义同名局部变量,这样程序会报错。报错信息显示为:在定义变量之前使用了变量。这样其实也验证了定义同名局部变量并不会修改全局变量的值。

2.2 修改全局变量

全局变量的值在函数内部也是可以进行修改的,但是需要特殊操作。好比生活中,公共汽车站牌是一个全局变量,你我都是函数,我们可以随意更改站牌位置吗?你觉得离家远,自己做主把站牌搬迁到家门口,那其他人怎么办?只能是经过特殊操作(比如政府进行调研,确认站牌位置的确不合理,然后提交申请,审批,最后审批通过)才可以搬迁。

看下方代码示例,如何修改全局变量:

代码语言:javascript
复制
# 定义全局变量
a = 18

# 定义函数
def testA():
    global a
    # 修改全局变量
    a = 999
    print(a)

testA()

执行结果如下:

代码语言:javascript
复制
999

总结:如果在函数中出现了 global全局变量的名字 ,那么这个函数就不会存在同名的局部变量,遇到同名变量名一律认为是全局变量, 变量名=数据 都认为是修改全局变量。如果在一个函数中需要对多个全局变量进行修改,那么可以使用:

代码语言:javascript
复制
global a, b

多个变量名之间使用逗号进行分割。

3.引用

大家在写论文,写作文时,经常会引用一些名人事例等,在 Python 中也会涉及引用。

代码语言:javascript
复制
>>> a = 1
>>> b = a
>>> print(b)
1

看以看到变量 b 引用了变量 a 的值。再来看一个小栗子:

代码语言:javascript
复制
a = [1, 2]
# b 引用 a 的值
b = a
# 对 a 进行操作
a.append(3)
# 查看 b 的值
print(b)

大家猜结果会是多少? [1,2] 还是 [1,2,3] 呢?买大买小,买定离手,开!

代码语言:javascript
复制
[1, 2, 3]

可以看到修改完 a 的值, b 也发生了修改。为什么呢?

答:列表是可变数据类型,它在向计算机申请资源时,就好像找计算机要了个箱子,用来存储元素, a变量存储的是箱子的地址(比如去超市将物品存储好后,箱子会返回给我们一个小条,上面有条形码可以开箱子,变量 a存储的就是这个小条)。变量 b 呢?存储的也是这个小条,所以当变量 a 打开箱子给里面多放了一只雪糕后,变量 b 再去开箱子,也会发现雪糕,因为大家保存的都是那个箱子的地址(即有条形码的小条)。

如果大家看到 “变量保存的是xx的引用”,引用指的就是计算机内存中的一个编号,也就是地址。

小扩展:

在 Python 中有个函数,可以用来查看变量的引用,即变量存储值的空间地址。它就是 id() ,我们可以将 id 返回的值理解为那块内存地址标识。此函数使用如下:

代码语言:javascript
复制
id(某变量)

分别查看两个变量的地址,通过判断它们值是否一致,从而判断是否为同一个值的引用。

3.1 引用当做实参传递

大家需要注意一点:Python 中函数参数是引用传递(并不是值传递)

1.给函数中传入一个不可变数据类型的时候,因为变量本身不可变,所以函数执行任何操作之后,该变量的值都不会改变。

代码语言:javascript
复制
>>> def function(somthing):
...     somthing = somthing * 2
...
>>> a = "我是测试用例"
>>> function(a)
>>> print(a)
我是测试用例

2.给函数中传入一个可变数据类型的时候,函数中的运算有可能会更改传入的参数变量。

代码语言:javascript
复制
>>> def function(somthing):
...     somthing += somthing
...
>>> a = [1, 2]
>>> function(a)
>>> print(a)
[1, 2, 1, 2]

可以看到更改了变量 a 的值。但是再看下方操作:

代码语言:javascript
复制
>>> def function(somthing):
...     somthing = somthing + somthing
...
>>> a = [1, 2]
>>> function(a)
>>> print(a)
[1, 2]

可以看到变量 a 的值没有被更改,都是相同的“相加赋值”,结果为什么不同呢?

这个牵扯到两个式子的底层执行原理:

1.第一种情况:

代码语言:javascript
复制
b += b
# += 是直接对 b 指向的空间进行修改
# 也就是说,在 b 引用的空间地址上直接操作,操作完,它还是指向该地址
# b 原先保存着 1 号柜子的钥匙,给柜子里多放了臭鸡蛋后,b 还拿着钥匙不舍得更换柜子

2.第二种情况:

代码语言:javascript
复制
b = b + b
# xx = xx + xx 是先把等号右边的结果计算出来,然后 b 指向新的结果
# 也就是说 b 指向了新的空间
# b 原先保存着 1 号柜子的钥匙,给柜子里多放了臭鸡蛋后,b 换了一个柜子,拿了 2 号柜子的钥匙

结合上述场景,理解示例中为什么可变数据类型有时会变有时不会变。

4.小知识点

4.1 可变和不可变类型

前面一直在说可变数据类型,不可变数据类型,在学习每种数据类型时也指出了其是否为可变类型,那么什么是可变与不可变数据类型?

所谓可变类型与不可变类型是指:数据能否直接进行修改,如果能直接修改那么就是可变,否则是不可变

代码语言:javascript
复制
def function(a):
    a += a # 结合前面学习,使用此方法直接在原数据上进行修改
# 演示不可变数据类型
a = 1
function(a)
print(a) # 输出结果为 1,发现未被修改。
# 演示可变数据类型
b = [1, 2, 3]
function(b)
print(b) # 输出结果为 [1, 2, 3, 1, 2, 3] ,发现原数据被修改

1.可变类型有:列表、字典、集合

2.不可变类型有:数字、字符串、元组

4.2 函数使用注意事项

1.想查看函数是否有返回值,可以看其是否有 return

2.结合实际情况设计函数是否需要返回值。

3.函数中出现多个 return ,执行其中一个后,函数立即调用完成。

4.在调用函数时假如需要传递实参,那么函数必须定义形参进行接收,而且实参个数由形参决定。(不要忘记缺省参数不定长参数的使用。)

5.在同一个程序中不能出现多个相同函数名的函数。

6.在同一个程序中避免变量名和函数名相同。

7.调用函数时,实参的个数和先后顺序应该同定义函数中要求的一致。而且函数有返回值的,必须使用变量来进行保存结果。

8.函数中定义的变量,只能在本函数中用(局部变量);函数外定义的变量,可以在所有的函数中使用(全局变量)。

作业

1.理解全局变量和局部变量以及他们的作用范围。(如果不明白,建议动手使用代码验证想法)

2.理解函数参数是引用传递这句话。

3.熟记哪些是可变数据类型,哪些是不可变数据类型。

4.明确函数使用规范,严格遵守注意事项。

今天的内容重在理解,因此作业就是多看几遍文章,有疑问的地方自己动手进行尝试,自己解决不了,欢迎大家留言询问。

下一篇
举报
领券