Python之路Python全局变量与局部变量、函数多层嵌套、函数递归

一、局部变量与全局变量

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']
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的位置

错误例子

  

分析:如果需要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之路 day3 全局变量、局部变量

    #!/usr/bin/env python # -*- coding:utf-8 -*- #Author:ersa """ 全局与局部变量 在子程序中定义的变量称为局部变 ...

  2. Python之路(第六篇)Python全局变量与局部变量、函数多层嵌套、函数递归

    一.局部变量与全局变量 1.在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量.全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序. 全局变量没有任何缩进,在任何位置都可 ...

  3. Python之路Python内置函数、zip()、max()、min()

    Python之路Python内置函数.zip().max().min() 一.python内置函数 abs() 求绝对值 例子 print(abs(-2)) all() 把序列中每一个元素做布尔运算, ...

  4. Python之路Python作用域、匿名函数、函数式编程、map函数、filter函数、reduce函数

    Python之路Python作用域.匿名函数.函数式编程.map函数.filter函数.reduce函数 一.作用域 return 可以返回任意值例子 def test1(): print(" ...

  5. 自学Python之路-Python基础+模块+面向对象+函数

    自学Python之路-Python基础+模块+面向对象+函数 自学Python之路[第一回]:初识Python    1.1 自学Python1.1-简介    1.2 自学Python1.2-环境的 ...

  6. 一文搞懂Python函数(匿名函数、嵌套函数、闭包、装饰器)!

    Python函数定义.匿名函数.嵌套函数.闭包.装饰器 目录 Python函数定义.匿名函数.嵌套函数.闭包.装饰器 函数核心理解 1. 函数定义 2. 嵌套函数 2.1 作用 2.2 函数变量作用域 ...

  7. 自学Python之路-Python核心编程

    自学Python之路-Python核心编程 自学Python之路[第六回]:Python模块       6.1 自学Python6.1-模块简介    6.2 自学Python6.2-类.模块.包  ...

  8. 自学Python之路-Python并发编程+数据库+前端

    自学Python之路-Python并发编程+数据库+前端 自学Python之路[第一回]:1.11.2 1.3

  9. 自学Python之路-Python网络编程

    自学Python之路-Python网络编程 自学Python之路[第一回]:1.11.2 1.3

随机推荐

  1. ACCESS中如何比较日期和时间,使用DateDiff函数

    DateDiff,语法如下:DateDiff( 间隔字符, 日期1, 日期2 [,firstdayofweek[, firstweekofyear]])一般使用 DateDiff( 间隔字符, 日期1 ...

  2. MobileSubstrate

    [MobileSubstrate] Cydia Substrate (formerly called MobileSubstrate) is the de facto framework that a ...

  3. codeforces:Roads in the Kingdom分析和实现

    题目大意:国家有n个城市,还有n条道路,每条道路连通两个不同的城市,n条道路使得所有n个城市相互连通.现在国家经费不足,要关闭一条道路.国家的不便度定义为国家中任意两个不同的城市之间的距离的最大值,那 ...

  4. 【HDU5391】Zball in Tina Town

    [题目大意] 一个球初始体积为1,一天天变大,第一天变大1倍,第二天变大2倍,第n天变大n倍.问当第 n-1天的时候,体积变为多少.注意答案对n取模. [题解] 根据威尔逊定理:(n-1)! mod ...

  5. php扩展开发1--添加函数

    目标:便携php扩展 要求实现 输出hello word 首先用的是php7.0.3   centos7.1或者centos6.+ 1.1 RPM安装PHP rpm -Uvh https://mirr ...

  6. SpringBoot24 SpringDataJPA环境搭建、实体类注解、关联查询

    1 版本说明 JDK:1.8 MAVEN:3.5 SpringBoot:2.0.4 IDEA:旗舰版207.2 MySQL:5.5 2 SpringDataJPA环境搭建(SpringBoot版本) ...

  7. Redis01 Redis服务端环境搭建

    1 前提准备 下载 VM centos6 安装包,安装好虚拟系统 2 安装远程连接工具 工具获取 2.1 SecureCRT.Xshell 连接远程服务器 2.2 WinSCP 向远程服务器发送文件 ...

  8. SQL CLR学习

    SQL CLR (SQL Common Language Runtime) 是自 SQL Server 2005 才出现的新功能,它将.NET Framework中的CLR服务注入到 SQL Serv ...

  9. 476. Number Complement 二进制中的相反对应数

    [抄题]: Given a positive integer, output its complement number. The complement strategy is to flip the ...

  10. SQL Server 2008 R2 Express 不能启动

    今天,新安装了Sql Server 2008 R2 Express,准备部署相应系统,在完成了数据库还原,系统部署以后,从浏览器里输入系统网址,出现登录页面,登录时报错,无法连上数据库.在查找原因的过 ...