##global关键字
※屏蔽(Shadowing) :当试图在函数内去修改全局变量,python就会使用屏蔽的方式保护全局变量,就是会在函数内部重新复制一个和全局变量一摸一样的局部变量放在栈里,这样修改的结果就会只修改到新创建的局部变量,不会影响到全局变量
※global:如果想要在函数内修改全局变量的值就用global关键字修饰
※内嵌函数
(python的函数是可以内嵌定义的,就是说允许在函数内部创建另一个函数,这种函数叫内嵌函数,或称为内部函数,但是要注意内部函数作用域都在外部函数之内,就比如下面在fun1()外面调用fun2()是会报错的)
※闭包(closure):函数式编程的重要语法结构
(不同的编程语言实现闭包的方式不同,python中。闭包从表现形式上定义为如果在一个内部函数里对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就会被认为是闭包)
(如上就是FunY是一个内部函数,他的外部作用域是FunX,然后他引用了外部作用域也就是FunX的变量x,所以说FunY函数是一个闭包,调用FunX返回的是一个函数对象,也就是函数的函数,要继续给参数才能返回闭包的结果)
(然而使用闭包的时候要注意的是,因为闭包的概念是由内部函数演变而来的,所以你也不能在外部函数的外部对内部函数进行调用,就上面的例子,就是在外面全局的域中直接调用FunY是会报错的)
※nonlocal:这个关键字和global关键字的使用方式是一样的
(在闭包中,外部函数的局部变量对内部函数的局部变量,事实上相当于之前讲的全局变量和局部变量的关系,在内部函数中,你只能对外部函数的局部变量尽量进行访问,但你不能对他进行修改,如下:内部函数就是fun2,外部函数就fun1,这里企图对外部函数fun1的局部变量进行修改,就报错了,因为当在执行return fun2的时候,就会跑到fun2里边去执行,而fun2的整个外部空间就是fun1的内部空间,包括局部变量x=5,对于fun2里边的x,fun1的x就相当于他的全局变量一样,但事实上他不是全局变量的,他是非全局变量的外部变量,就是在fun2的外部作用域,当在fun2里试图对x进行修改,那么外部函数的x就会被屏蔽起来,这跟我们的全局变量和局部变量的道理是一样,下面的报错是意思就是不能对未定义的变量进行赋值,就是外部的x被屏蔽了,x是没有定义的)
(解决办法1就是:在python3之前只能间接地通过容器类型来存放,因为容器类型不是存放在栈里边,所以x不会被屏蔽起来,容器就是什么都可以往里边扔的,那就是列表,如下改造)
(解决办法2就是:在python3之后可以用关键字nonlocal 如下:把x强制声明为他不是一个局部变量)
##温故知新之习题
0.如果希望在函数中修改全局变量的值,应该使用什么关键字?
答:global 关键字来
举个例子:
>>> count = 5
>>> def MyFun():
global count
count = 10
print(count)
>>> MyFun()
10
>>> count
10
1.在嵌套的函数中,如果希望在内部修改外部函数的局部变量,应该使用什么关键字?
答:nonlocal 关键字
举个例子:
>>> def Fun1():
x = 5
def Fun2():
nonlocal x
x *= x
return x
return Fun2()
>>> Fun1()
25
2. Python 的函数可以嵌套,但要注意访问的作用域问题哦,请问以下代码存在什么问题呢?
def outside():
print('I am outside!')
def inside():
print('I am inside!')
inside()
答:使用嵌套函数要注意一点就是作用域问题,inside() 函数是内嵌在 outside() 函数中的,所以 inside() 是人妻,除了身为老公的 outside() 可以碰(调用),在外边或者别的函数体里是无法对其进行调用的。
正确的应该是:
def outside():
print('I am outside!')
def inside():
print('I am inside!')
inside()
outside()
3. 请问为什么代码 A 没有报错,但代码 B 却报错了?应该如何修改?
代码A:
def outside():
var = 5
def inside():
var = 3
print(var)
inside()
outside()
代码B:
def outside():
var = 5
def inside():
print(var)
var = 3
inside()
outside()
答:仔细一看报错的内容是:UnboundLocalError: local variable ‘var’ referenced before assignment,说的是变量 var 没有被定义就拿来使用,肯定错啦!
这里 outside() 函数里有一个 var 变量,但要注意的是,内嵌函数 inside() 也有一个同名的变量,Python 为了保护变量的作用域,故将 outside() 的 var 变量屏蔽起来,因此此时是无法访问到外层的 var 变量的。
4. 请问如何访问 funIn() 呢?
def funOut():
def funIn():
print('宾果!你成功访问到我啦!')
return funIn()
答:只需要直接调用 funOut() 即可:
5. 请问如何访问 funIn() 呢?
def funOut():
def funIn():
print('宾果!你成功访问到我啦!')
return funIn
答:区别于上一题,这里你就需要用 funOut()() 访问啦
6. 以下是“闭包”的一个例子,请你目测下会打印什么内容?
def funX():
x = 5
def funY():
nonlocal x
x += 1
return x
return funY
a = funX()
print(a())
print(a())
print(a())
答:
会打印:
6
7
8
##动动手
0. 请用已学过的知识编写程序,统计下边这个长字符串中各个字符出现的次数并找到小甲鱼送给大家的一句话。
(由于我们还没有学习到文件读取方法,大家下载后拷贝过去即可)
答:
str1 = '''拷贝过来的字符串'''
list1 = []
for each in str1:
if each not in list1:
if each == '\n':
print('\\n', str1.count(each))
else:
print(each, str1.count(each))
list1.append(each)
1. 请用已学过的知识编写程序,找出小甲鱼藏在下边这个长字符串中的密码,密码的埋藏点符合以下规律:
a) 每位密码为单个小写字母
b) 每位密码的左右两边均有且只有三个大写字母
答:
str1 = '''ABSaDKSbRIHcRHGcdDIF'''
countA = 0 # 统计前边的大写字母
countB = 0 # 统计小写字母
countC = 0 # 统计后边的大写字母
length = len(str1)
for i in range(length):
if str1[i] == '\n':
continue
"""
|如果str1[i]是大写字母:
|-- 如果已经出现小写字母:
|-- -- 统计后边的大写字母
|-- 如果未出现小写字母:
|-- -- 清空后边大写字母的统计
|-- -- 统计前边的大写字母
"""
if str1[i].isupper():
if countB:
countC += 1
else:
countC = 0
countA += 1
"""
|如果str1[i]是小写字母:
|-- 如果小写字母前边不是三个大写字母(不符合条件):
|-- -- 清空所有记录,重新统计
|-- 如果小写字母前边是三个大写字母(符合条件):
|-- -- 如果已经存在小写字母:
|-- -- -- 清空所有记录,重新统计(出现两个小写字母)
|-- -- 如果该小写字母是唯一的:
|-- -- -- countB记录出现小写字母,准备开始统计countC
"""
if str1[i].islower():
if countA != 3:
countA = 0
countB = 0
countC = 0
else:
if countB:
countA = 0
countB = 0
countC = 0
else:
countB = 1
countC = 0
target = i
"""
|如果前边和后边都是三个大写字母:
|-- 如果后边第四个字母也是大写字母(不符合条件):
|-- -- 清空记录B和C,重新统计
|-- 如果后边仅有三个大写字母(符合所有条件):
|-- -- 打印结果,并清空所有记录,进入下一轮统计
"""
if countA == 3 and countC == 3:
if i+1 != length and str1[i+1].isupper():
countB = 0
countC = 0
else:
print(str1[target], end='')
countA = 3
countB = 0
countC = 0