一、局部变量与全局变量

1、在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。

全局变量没有任何缩进,在任何位置都可以调用。

子程序:如用def定义的函数。

作用域

一个标识符的可见范围,这就是标识符的作用域。一般常说的是变量的作用域

全局作用域(global):在整个程序运行环境中都可见

局部作用域:在函数、类等内部可见;局部变量使用范围不能超过其所在的局部作用域。

例子

NAME = "nicholas"
def change_NAME():
print("change_NAME", NAME)
change_NAME()
print(NAME)

  

  

输出结果

change_NAME nicholas
nicholas

  

分析:NAME = "nicholas"就是全局变量,在
change_NAME()函数体内可以直接调用打印出“change_NAME nicholas”

2、当全局变量与局部变量同名时:

在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。

例子:

NAME = "nicholas"
def change_NAME():
NAME = "niubi"
print("change_NAME", NAME)
change_NAME()
print(NAME)

  

输出结果

change_NAME niubi
nicholas

  

分析:当全局变量与局部变量同名时:在 def change_NAME():函数内部,
执行print("change_NAME", NAME)语句时,这里的NAME优先调用函数内部的值,函数执行结束后执行print(NAME)语句,全局变量NAME = "nicholas"起作用。

3、如果函数内部无global关键字

优先读取局部变量,如果没有局部变量则读取全局变量,此时无法对全局变量进行赋值。

但是对于可变对象可以对内部元素进行操作(如append()pop()).

大前提:无global关键字

a、有声明(同名)局部变量
例子

name = ["pony","jack"]
print(1,name)
def change_name():
name = "nicholas"
print("change_name", name)
change_name()
print(2,name)

  

输出结果

1 ['pony', 'jack']
change_name nicholas
2 ['pony', 'jack']

  

分析:这里无golbal关键字,执行 print(1,name)语句时读取全局变量name = ["pony","jack"],之后执行change_name()函数,在函数里面nema被赋值为"nicholas"
执行print("change_name", name)语句,这里的name优先读取函数内部的局部变量name = "nicholas"
输出change_name nicholas。之后change_name()函数结束。
执行print(2,name)语句。这里仍然读取全局变量name = ["pony","jack"]。

b、无声明(同名)局部变量
例子

name = ["pony","jack"]
print(1,name)
def change_name():
print(3, name)
name.append("nicholas")
print(4,name)
change_name()
print(2,name)

  

输出结果

1 ['pony', 'jack']
3 ['pony', 'jack']
4 ['pony', 'jack', 'nicholas']
2 ['pony', 'jack', 'nicholas']

  

分析:无global关键字,针对全局变量如果是可变对象,可以对内部元素进行操作。

4、如果函数中有global关键字,变量本质上就是全局变量,可读取可赋值。

a、有声明(同名)局部变量

例子

NAME = "nicholas"
print(1,NAME)
def change_NAME():
global NAME
NAME = "niubi"
print("change_NAME", NAME)
change_NAME()
print(2,NAME)

  

输出结果

1 nicholas
change_NAME niubi
2 niubi

  

分析:在执行print("1",NAME)语句时,NAME使用全局变量,然后执行change_NAME()函数,在函数内部有global关键词声明,之后执行NAME = "niubi",执行完这句之后整个程序的NAME变量的值就被修改为"niubi"。
继续输出change_NAME niubi,函数结束。

最后执行print("2",NAME)语句,由于NAME在函数内部被修改为"niubi",所以这里输出
2 niubi

例子2

name = ["pony","jack"]
print(1,name)
def change_name():
global name
name = ["nick"]
name.append("nicholas")
print(3,name)
change_name()
print(2,name)

  

输出结果

1 ['pony', 'jack']
3 ['nick', 'nicholas']
2 ['nick', 'nicholas']

  

分析:
开始name = ["pony","jack"]是全局变量,之后执行change_name()函数吗,在函数中有global关键字,之后针对name做的修改都相当于将name作为全局变量来修改。

c、注意global的位置

错误例子

name = ["pony","jack"]
def change_name():
name = "nick"
global name
name.append("nicholas")
change_name()
print(name)

  

分析:如果需要global对全局变量进行修改这里的global不能放在name = "nick"下面。

5、代码规范:全局变量字母全部大写,局部变量变量名小写。

二、多层函数的嵌套和作用域

(1)一定要注意函数要先定义,后使用
例子1

def test1():
print("test1")
def test2():
print("test2")
test1()
test2()

  

分析:这样是可以的,先定义函数,再使用函数

错误例子

def test1():
print("test1")
test2()
def test2():
print("test2")
test1()

  

分析:这样的test2()就无法执行。

(2)在函数内定义的函数 在外面不能用到

例子2

def outer():
def inner():
print('inner')
print('outer')
inner()
outer()

  

分析:函数有可见范围,这就是作用域的概念。内部函数不能被外部直接使用。

例子

def foo():
print("foo")
too()
def too():
print("too")
foo()

  

分析:这里执行顺序是加载def foo():
加载def too():然后再执行foo(),所以这里不会报错。

(3)分析多层嵌套函数执行过程及结果
例子

NAME = 'nicholas'
def jack():
name = "jack"
print(name)
def pony():
name = "pony"
print(name)
def charles():
name = 'charles'
print(name)
print(name)
charles()
pony()
print(name)
jack()

  

输出结果:

jack
pony
pony
charles
jack

  

分析:

执行过程如下图

执行顺序:1----2----3----3.1----3.2----3.3----3.4----3.3.1----
3.3.2----3.3.3----3.3.4----3.3.5--3.3.3.1--3.3.3.2----3.5

1 首先执行NAME = 'nicholas'语句,

2 加载def jack():函数到内存进行编译,但不执行

3 调用jack()函数,开始执行

3.1 执行name = "jack"语句

3.2 执行print(name)语句,这里由于没有global关键字,优先读取局部变量name = "jack",所以这里输出jack

3.3 加载def pony():函数到内存进行编译,但不执行

3.4 调用pony():函数,开始执行

3.3.1 执行name = "pony"语句,这里是一个局部变量

3.3.2 执行print(name)语句,这里由于没有global、nonlocal关键字,优先读取局部变量name = "pony",所以这里输出pony

3.3.3 加载charles():函数到内存进行编译,但不执行

3.3.4 执行print(name)语句,这里由于没有global、nonlocal关键字,优先读取同一层级的局部变量name = "pony",所以这里输出pony

3.3.5 调用charles():函数,开始执行

3.3.3.1 执行name = 'charles'语句,这里是个局部变量

3.3.3.2 执行print(name)语句,优先读取局部变量name = "charles",所以这里输出charles

~~charles():函数结束

~~pony():函数

3.5 执行执行print(name)语句,优先使用同层级的局部变量name = "jack",所以这里输出jack。

~~整体结束

例子

name = "nicholas"
def outer():
name = "nick"
def inner():
print(name)
print(name)
inner()
outer()

  

输出结果

nick
nick

  分析:注意这里的inner()函数内部的print(name)语句,这里仍然是优先使用outer()函数内部的局部变量name = "nick",而非全局变量。

(4)

nonlocal关键词
nonlocal,指定上一级变量,如果没有就继续往上直到找到为止
例子
看这个程序,分析输出过程和结果。

def scope_test():
def do_local():
spam = "local spam"
def do_nonlocal():
nonlocal spam
spam = "nonlocal spam"
def do_global():
global spam
spam = "global spam"
spam = "test spam"
do_local()
print("After local assignment:", spam)
do_nonlocal()
print("After nonlocal assignment:", spam)
do_global()
print("After global assignment:", spam)
scope_test()
print("In global scope:", spam)

  

输出结果

After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam

  

分析:
程序执行步骤如图

从1开始
1--2--2.1--2.2--2.3--2.4--2.5--2.5.1--2.5.2--2.6--2.7--2.7.1--2.7.2--2.8

--2.9--2.9.1--2.9.2--2.10--2.11

下面具体分析下程序执行的过程

1 将def scope_test():函数体作为一个整体加载到内存中,但不执行

2 调用def scope_test():开始执行

2.1 将def do_local():函数体作为一个整体加载到内存中,但不执行

2.2 将def do_nonlocal(): 函数体作为一个整体加载到内存中,但不执行

2.3 将 def do_global(): 函数体作为一个整体加载到内存中,但不执行

2.4 执行 spam = "test spam"

2.5 调用 def do_local():函数

2.5.1 执行 def do_local():函数

2.5.2 执行 spam = "local spam"

--完成2.5.2之后 def do_local():函数结束,其所占的内存被回收, spam =

"local spam"数据被销毁

2.6 执行print("After local assignment:", spam)语句

由于没有global关键字,这里优先读取局部变量,即spam = "test spam"

打印出After local assignment: test spam

2.7 调用do_nonlocal()函数

2.7.1 执行def do_nonlocal():

遇到 nonlocal 声明,nonlocal关键字用来在函数外层(非全局)变量。

这里的外层即为def scope_test():这个作用域内

2.7.2 执行spam = "nonlocal spam"语句

这时def scope_test():这个作用域内由以前的spam = "test spam"被重新覆盖为

spam = "nonlocal spam"

--do_nonlocal()函数体结束

2.8 执行 print("After nonlocal assignment:", spam)语句

由于spam被重新赋值为"nonlocal spam",这里输出

After nonlocal assignment: nonlocal spam

2.9 调用do_global()函数

2.9.1 执行def do_global(): 函数

2.9.2 执行 spam = "global spam" 语句

遇到global声明,global关键字用来在函数整体作用域使用全局变量。类似于在

def scope_test():上面写了一句spam = "global spam"

--def do_global(): 函数体结束

2.10 执行print("After global assignment:", spam)语句

由于这一层级作用域没有global关键字,这里优先读取局部变量,即被修改过一次的

spam = "nonlocal spam"

这里输出After global assignment: nonlocal spam

2.11执行print("In global scope:", spam)语句

由于在2.9.2 spam被声明了全局变量,即spam = "global spam"

所以这里输出

In global scope: global spam

例子2

name = "jack"
def foo():
name = "nick"
print(name)
def too():
nonlocal name
name = "nicholas"
print(1,name)
too()
print(name)
foo()

  输出结果

nick
1 nicholas
nicholas

  分析:注意这里的def too():函数内print(1,name)语句仍然优先读取局部变量name = "nicholas"。

三、递归

1、递归的定义

如果在调用一个函数的过程中直接或间接调用自身本身,那么这种方法叫做递归。

2、递归的特点

a、递归必须有一个明确的结束条件(基例)。
b、每次进入更深一层递归时,问题规模相比上次递归都应有所减少。
c、递归效率不高,递归层次过多会导致栈溢出。

3、递归的执行过程

例子

def calc(n):
print(n)
if int(n/2) ==0:
return n
return calc(int(n/2))
calc(10)

  

输出结果

10
5
2
1

  

分析执行过程:

具体过程

(1)执行def calc(n):语句,将calc(n)函数加载到内存中进行编译,但不执行

(2)执行calc(10)语句,调用calc(n)函数,将n = 10 传入calc(n)函数

(3)执行print(n)语句,此时n = 10,打印10

判断n/2是否等于0,10/2 = 5不等于0

执行retun语句,return调用calc(n)函数,

此时具体是执行calc(int(10/2))即calc(5)

此层函数暂停,等待calc(5)返回值

(4)执行print(n)语句,此时n = 5,打印5

判断n/2是否等于0,5/2 = 2不等于0

执行retun语句,return调用calc(n)函数,

此时具体是执行calc(int(5/2))即calc(2)

此层函数暂停,等待calc(2)返回值

(5)执行print(n)语句,此时n = 2,打印2

判断n/2是否等于0,2/2 = 1不等于0

执行retun语句,return调用calc(n)函数,

此时具体是执行calc(int(2/2))即calc(1)

此层函数暂停,等待calc(1)返回值

(6)执行print(n)语句,此时n = 1,打印1

判断n/2是否等于0,1/2 = 2等于0,

执行if条件下的retun语句,return n 给上一层函数,

即return 1给上层函数

(7)将1传给calc(1),calc(1)得到值为1 ,

return calc(1)即return 1,再次将1传给上层的return calc(2),

calc(2)得到值为1,再次将1传给上层的return calc(5),

calc(5)得到值为1,最后将1传给calc(10),

即calc(10)= 1。

这里可以打印下calc(10)的值

def calc(n):
print(n)
if int(n / 2) == 0:
return n
return calc(int(n / 2))
v = calc(10)
print("calc(10)是",v)

  输出结果

10
5
2
1
calc(10)是 1

  

例子2

import time
person_list=['Pony','Charles','Richard ','Jack']
print("How can I make good money?")
def ask(person_list):
print('-'*60)
if len(person_list) == 0:
return "I don't know"
person=person_list.pop(0)
if person == "Jack":
return "%s say:Better have a dream, in case it comes true someday." %person
print('hi Boss[%s],How can I make good money?' %person)
print("%s replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask %s..." %(person,person_list))
time.sleep(10)
res=ask(person_list)
#print('%s say: %res' %(person,res))#注释语句
return res res = ask(person_list) print(res)

  

输出结果

How can I make good money?
------------------------------------------------------------
hi Boss[Pony],How can I make good money?
Pony replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Charles', 'Richard ', 'Jack']...
------------------------------------------------------------
hi Boss[Charles],How can I make good money?
Charles replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Richard ', 'Jack']...
------------------------------------------------------------
hi Boss[Richard ],How can I make good money?
Richard replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Jack']...
------------------------------------------------------------
Jack say:Better have a dream, in case it comes true someday.

  

如果取消上面print('%s say: %res' %(person,res))注释,执行这一语句,可以看出return返回的过程
如下

import time
person_list=['Pony','Charles','Richard ','Jack']
print("How can I make good money?")
def ask(person_list):
print('-'*60)
if len(person_list) == 0:
return "I don't know"
person=person_list.pop(0)
if person == "Jack":
return "%s say:Better have a dream, in case it comes true someday." %person
print('hi Boss[%s],How can I make good money?' %person)
print("%s replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask %s..." %(person,person_list))
time.sleep(1)
res=ask(person_list)#第一处
print('%s say: %res' %(person,res))
return res res = ask(person_list)#第二处 print(res)

  

输出结果

How can I make good money?
------------------------------------------------------------
hi Boss[Pony],How can I make good money?
Pony replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Charles', 'Richard ', 'Jack']...
------------------------------------------------------------
hi Boss[Charles],How can I make good money?
Charles replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Richard ', 'Jack']...
------------------------------------------------------------
hi Boss[Richard ],How can I make good money?
Richard replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Jack']...
------------------------------------------------------------
Richard say: 'Jack say:Better have a dream, in case it comes true someday.'es
Charles say: 'Jack say:Better have a dream, in case it comes true someday.'es
Pony say: 'Jack say:Better have a dream, in case it comes true someday.'es
Jack say:Better have a dream, in case it comes true someday.

  

分析:最后的返回结果是Richard返回给Charles,Charles返回给Pony
第一处的res=ask(person_list) 就算执行完了,res得到Jack say:Better have a dream, in case it comes true someday.

然后return给函数外的res,最后打印这句话。

Python之路(第六篇)Python全局变量与局部变量、函数多层嵌套、函数递归的更多相关文章

  1. Python之路(第八篇)Python内置函数、zip()、max()、min()

    一.python内置函数 abs() 求绝对值 例子 print(abs(-2)) all() 把序列中每一个元素做布尔运算,如果全部都是true,就返回true, 但是如果是空字符串.空列表也返回t ...

  2. 【Python之路】特别篇--Python装饰器

    前情提要 1. 作用域 在python中,函数会创建一个新的作用域.python开发者可能会说函数有自己的命名空间,差不多一个意思.这意味着在函数内部碰到一个变量的时候函数会优先在自己的命名空间里面去 ...

  3. Python之路(第七篇)Python作用域、匿名函数、函数式编程、map函数、filter函数、reduce函数

    一.作用域 return 可以返回任意值例子 def test1(): print("test1") def test(): print("test") ret ...

  4. 【Python之路】特别篇--Python文件操作

    文件操作 open函数,该函数用于文件处理 操作文件时,一般需要经历如下步骤: (1)打开文件 (2)操作文件 一.打开文件 文件句柄 = open('文件路径', '模式','编码') 打开文件时, ...

  5. 【Python之路】第九篇--Python基础之线程、进程和协程

    进程与线程之间的关系 线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除.线程可与属于同一进程的其它线程共享进程所拥有的全 ...

  6. Python之路(第五篇) Python基本数据类型集合、格式化、函数

    一.变量总结 1.1 变量定义 记录某种状态或者数值,并用某个名称代表这个数值或状态. 1.2 变量在内存中的表现形式 Python 中一切皆为对象,数字是对象,列表是对象,函数也是对象,任何东西都是 ...

  7. 【Python之路】特别篇--Python内置函数

    abs() 求绝对值 i = abs(-100) print(i) # 100 all() 循环里面的参数 如果每个元素都为真,那么all返回值为真  假: 0 False None "&q ...

  8. 【Python之路】特别篇--Python面向对象(进阶篇)

    上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...

  9. 【Python之路】特别篇--Python切片

    字符串切片操作 切片操作符是序列名后跟一个方括号,方括号中有一对可选的数字,并用冒号分割. 注意: 数是可选的,而冒号是必须的. consequence[start:end:step] 切片操作符中的 ...

随机推荐

  1. OTU(operational taxonomic units),即操作分类单元

    转自http://www.dxy.cn/bbs/topic/35655953 1.OTU是什么? OTU(operational taxonomic units),即操作分类单元.通过一定的距离度量方 ...

  2. 解题10(LongestSubStrBetweenAB)

    题目描述 查找两个字符串a,b中的最长公共子串.若有多个,输出在较短串中最先出现的那个. 输入描述: 输入两个字符串 输出描述: 返回重复出现的字符 示例1 输入 abcdefghijklmnop a ...

  3. python3替换文件的内容

    目标:替换文件中的字符串内容   方法1:使用fileinput包   import fileinput for line in fileinput.input(“要修改的文件名", inp ...

  4. tab template

    <div class="box"> <div class="box-body"> <div class="nav-tab ...

  5. html中相对(relative),绝对(absolute)位置以及float的学习和使用案例 (转)

    这几天着手于CSS的研究,研究的原因主要是工作需要,最近发现如果做前端仅仅会javascript很难尽善尽美,当然懂样式和html在一定程度上可以让我们更近一步. css较为简单,由于个人擅长编写代码 ...

  6. NDK环境搭建方法2

    1.新建项目NDKDemo3 2.新建com.example.shixm.ndkdemo3.MyNdk.java 3.右键main文件夹,New->Folder->JNI Folder 4 ...

  7. 整理一些好用的css, javascript资源网站等

    CSS: CSS3信息:http://www.css3.info/ css3生成器:http://css3generator.com/ css3 cross brower生成器:http://css3 ...

  8. 微信小程序开发——获取小程序带参二维码全流程

    前言: 想要获取微信小程序带参数二维码,如这种: 官方文档只说了获取小程序码和二维码的三种接口及调用(参考链接:https://developers.weixin.qq.com/miniprogram ...

  9. [剑指Offer]39-数组中出现次数超过一半的数字(快排延申,找第k大数同理)

    题目链接 https://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163?tpId=13&tqId=11181&t ...

  10. c#: 打开文件夹并选中文件

    一.常规方法 给定一个文件路径,打开文件夹并定位到文件,通常所用shell命令为:explorer.exe /select,filepath. c#以进程启动之为: if (File.Exists(f ...