Crossin的编程教室

标题: 【Python 第71课】变量的作用域 [打印本页]

作者: crossin先生    时间: 2014-6-17 18:38
标题: 【Python 第71课】变量的作用域


在写代码的时候,免不了要使用变量。但程序中的一个变量并不一定是在哪里都可以被使用,根据情况不同,会有不同的“有效范围”。看这样一段代码:

def func(x):
  print 'X in the beginning of func(x): ', x
  x = 2
  print 'X in the end of func(x): ', x

x = 50
func(x)
print 'X after calling func(x): ', x

输出:
X in the beginning of func(x):  50
X in the end of func(x):  2
X after calling func(x):  50

变量 x 在函数内部被重新赋值。但在调用了函数之后,x 的值仍然是50。为什么?

这就得说一下变量的“作用域”:

当函数内部定义了一个变量,无论是作为函数的形参,或是另外定义的变量,它都只在这个函数的内部起作用。函数外即使有和它名称相同的变量,也没有什么关联。这个函数体就是这个变量的作用域。像这样在函数内部定义的变量被称为“局部变量”。

要注意的是,作用域是从变量被定义的位置开始。像这样的写法是有问题的:

def func():
  print y
  y = 2
  print y        

报错:
UnboundLocalError: local variable 'y' referenced before assignment

因为在 y = 2 之前,y 并不存在,调用 y 的值就会出错。

回到开始那个例子:
在函数 func 外部,定义的变量 x,赋值为 50,作为参数传给了函数 func。而在函数 func 内部,变量 x 是形参,它的作用域是整个函数体内部。它与外面的那个 x 没有关系。只不过它的初始值是由外面那个 x 传递过来的。

所以,虽然函数体内部的 x 被重新赋值为 2,也不会影响外面那个 x 的值。


不过有时候,我们希望能够在函数内部去改变一些变量的值,并且这些变量在函数外部同样被使用到。怎么办?

一种方法是,用 return 把改变后的变量值作为函数返回值传递出来,赋值给对应的变量。比如开始的那个例子,可以在函数结尾加上
return x
然后把调用改为
x = func(x)

还有一种方法,就是使用“全局变量”。

在 Python 的函数定义中,可以给变量名前加上 global 关键字,这样其作用域就不再局限在函数块中,而是全局的作用域。

通过 global 改写开始的例子:

def func():
  global x
  print 'X in the beginning of func(x): ', x
  x = 2
  print 'X in the end of func(x): ', x

x = 50
func()
print 'X after calling func(x): ', x

输出:
X in the beginning of func(x):  50
X in the end of func(x):  2
X after calling func(x):  2

函数 func 不再提供参数调用。而是通过 global x 告诉程序:这个 x 是一个全局变量。于是函数中的 x 和外部的 x 就成为了同一个变量。这一次,当 x 在函数 func 内部被重新赋值后,外部的 x 也随之改变。


前面讲的局部变量和全局变量是 Python 中函数作用域最基本的情况。实际上,还有一些略复杂的情况,比如:

def func():
  print 'X in the beginning of func(x): ', x
  # x = 2
  print 'X in the end of func(x): ', x

x = 50
func()
print 'X after calling func(x): ', x

输出:
X in the beginning of func(x):  50
X in the end of func(x):  50
X after calling func(x):  50

程序可以正常运行。虽然没有指明 global,函数内部还是使用到了外部定义的变量。然而一旦加上
x = 2
这句,程序就会报错。因为这时候,x 成为一个局部变量,它的作用域从定义处开始,到函数体末尾结束。

建议在写代码的过程中,显式地通过 global 来使用全局变量,避免在函数中直接使用外部变量。


作者: jpjlqone    时间: 2014-6-18 11:11
让老师知道你写的每篇都会有人认真看,只要老师一直更新,就会有人一直支持。
作者: jpjlqone    时间: 2014-6-18 11:14
建议老师写课程的时候除了基础介绍外,更多地把在自己的应用技巧渗透进去,比重更大些,因为基础教程可能很好搜索、学习,但是经验和技能分享就更显珍贵了。
作者: crossin先生    时间: 2014-6-18 16:44
jpjlqone 发表于 2014-6-18 11:14
建议老师写课程的时候除了基础介绍外,更多地把在自己的应用技巧渗透进去,比重更大些,因为基础教程可能很 ...

好的,谢谢你的建议

作者: BlackBear黑熊    时间: 2014-6-26 10:58
有个感觉:
学编程语言和用Excel有点相通
Excel打开看到的都是最基础的,这就像python的基础语法一样,
你要用Excel做好一件事,就得去学它里面的函数了宏了什么的,这就和Python的函数 模块 库 一样
你要真正想学好Excel实现一个突破,最好的办法就是去做一个东西,边做边查函数库,
而Python应该也是这样吧?

作者: crossin先生    时间: 2014-6-27 14:31
BlackBear黑熊 发表于 2014-6-26 10:58
有个感觉:
学编程语言和用Excel有点相通
Excel打开看到的都是最基础的,这就像python的基础语法一样,

说得很对
作者: BlackBear黑熊    时间: 2014-7-8 22:47
更新一下
作者: liu-pengfei    时间: 2014-9-27 00:48
变量的“作用域”,的确很重要,看了好久,实验了几种代码,明白了。
作者: sun_yuanzy    时间: 2014-10-21 18:59
攒个积分吧
作者: muneer    时间: 2015-4-14 15:00
每节课的配图都相当赞啊~
作者: hanxuejiao    时间: 2015-12-9 17:02
先生讲的超级超级好!受益匪浅!不知道啥时候才会出下一节课呢?期待期待~~~
作者: crossin先生    时间: 2015-12-9 21:17
hanxuejiao 发表于 2015-12-9 17:02
先生讲的超级超级好!受益匪浅!不知道啥时候才会出下一节课呢?期待期待~~~ ...

关注微信,有些新的还没有放到网站上来
作者: 草办    时间: 2015-12-15 15:49
get
作者: 我是一个小菜鸟    时间: 2016-1-11 11:49
变量的作用域,不同的地方,不同的身份,就像象棋里面的像(相),一直出不了河
作者: 我是一个小菜鸟    时间: 2016-1-11 11:52
我是一个小菜鸟 发表于 2016-1-11 11:49
变量的作用域,不同的地方,不同的身份,就像象棋里面的像(相),一直出不了河 ...

python课程共71课吗?

作者: crossin先生    时间: 2016-1-11 12:18
我是一个小菜鸟 发表于 2016-1-11 11:52
python课程共71课吗?

目前到73课,基础基本讲完了
http://res.crossin.me/wechat/python.html
作者: 妙舞汉宫人    时间: 2016-8-11 10:56
muneer 发表于 2015-4-14 15:00
每节课的配图都相当赞啊~

我也发现了,挺符合每节讲的内容的
作者: brahmagupta    时间: 2017-3-4 22:05
71节课 完结留念
作者: crossin先生    时间: 2017-3-5 01:01
brahmagupta 发表于 2017-3-4 22:05
71节课 完结留念


作者: fly    时间: 2017-8-18 16:12
在微信上看完了,来这里攒个积分谢谢Crossin先生!
作者: ZFlyee    时间: 2018-3-11 17:59
  File "E:/Python/Projects/Exercise/lesson71 变量的作用域.py", line 2
    global x
    ^
SyntaxError: name 'x' is parameter and global

Process finished with exit code 1

===========
这里为啥说x既是参数又是全局变量?

作者: crossin先生    时间: 2018-3-12 16:38
ZFlyee 发表于 2018-3-11 17:59
File "E:/Python/Projects/Exercise/lesson71 变量的作用域.py", line 2
    global x
    ^

你把x作为函数参数了吧
提问请提供完整代码




欢迎光临 Crossin的编程教室 (https://bbs.crossincode.com/) Powered by Discuz! X2.5