全局变量和局部变量
函数的嵌套定义
global, nonlocal语句
lambda 表达式
局部变量:
定义在函数内部的变量称为局部变量(函数的形参也是局部变量);
局部变量只能在函数内部使用;
局部变量在函数调用时才能够被创建,在函数调用结束之后会自动销毁;
全局变量:
定义在函数外部,模块内部的变量称为全局变量; 函数名也是全局变量;
所有的函数都可以直接访问全局变量,但函数内部不能直接通过赋值语句来改变全局变量的绑定关系;
#veribale.py #exercise #创建一个全局变量: # L = [] # 写一个函数 # def input_number(): # 读入正整数,放到L列表内 L = [] def input_number(): lst = [] while True: n = int(input("请输入整数:") or '-1') if n < 0: break lst.append(n) #走到此时,lst里是本次函数调用时用户输入的整数 return lst print(L) L += input_number() #输入1 2 3 print(L) L += input_number() #输入4 5 print(L) #[1,2,3,4,5] L = [1,2,3] def fx(L): L += [4,5] fx(L) print(L)
局部变量说明:
1.在函数内首次对变量赋值是创建局部变量,再次为变量赋值是修改局部变量的绑定关系;
2.在函数内部的赋值语句不会对全局变量造成影响;
3.局部变量只能在其被声明的函数内部访问,而全局变量可以在整个模块内访问;
尽量少用全局变量,因为作用域大;列表不分全局和局部,只有变量才分全局和局部。
>>> L = [1,2,3] >>> def fx(L): ... L += [4,5] #注意这里L赋值是修改的列表合并,未修改原有的绑定关系。 ... >>> fx(L) >>> print(L) [1, 2, 3, 4, 5] >>>
globals()函数和locals函数:
globals()返回当前全局作用域内变量的字典;
locals()返回当前局部作用域内的变量字典;
#globals_locals_function.py a = 1 b = 2 c = 3 def fx(c,d): e = 300 #此处有几个局部变量 print('locals()返回', locals()) print('globals() 返回', globals()) print(globals()['c']) #函数内,返回全局变量字典,通用键值取全局变量“c”的值; fx(100, 200)
函数变量:
函数名是变量,它在创建时绑定一个函数;
一个函数可以作为另一个函数实参传递;
函数作为另一个函数的返回值;
示例: #function_variable.py def f1(): print("hello f1") def f2(): print("hello f2") fx = f1 #注意此处f1没有加() fx() #调用f1 f1() #调用f1 f1 = f2 #让f1改变绑定关系,去绑定f2 f1() #调用f2 f2 = fx f2() #调用f1 #交换法(三次交换赋值) #function_give_args.py def fz(fn): print('fn绑定的是', fn) fn() #调用fn绑定的函数,此处调用谁是看调用者传过来的参数 fz(f1) fz(f2)
#案例
# 看懂如下代码是什么事?
def myinput(fn):
L = []
while True:
x = int(input("请输入大于0的数") or '-1')
if x < 0:
break
L.append(x)
return fn(L) #<<<注意此处调用
#
print(myinput(max))
print(myinput(min))
print(myinput(sum))
#function_return_other_function.py
#此示例示意get_op这个函数可以返回其它的函数
def get_op():
s = input('请输入您要做的操作:')
if s == '求最大':
return max
elif s == '求最小':
return min
elif s == '求和':
return sum
L = [1, 2, 3, 4]
fx = get_op()
print(fx(L))
函数的嵌套定义:
函数嵌套定义是指一个函数里用def 语句来创建其它函数的情况;
示例见:function_embed_def.py
python的作用域:name sapce
作用域也叫命字空间,是访问变量时查找变量名的范围空间;
python的四个作用域 LEGB
作用域 英文解释 英文简写
局部作用域(函数内) Local(function) L
外部嵌套函数作用域 Enclosing function locals E
函数定义所在模块(文件)的作用域 Globals(module) G
python 内置模块的作用域 Builtin(python) B
示例:namespace.py v = 100 def fun1(): v = 200 print('fun1.v = ', v) def fun2(): v = 300 print('fun2.v = ', v) fun2() fun1() print('全局.v = ', v)
变量名的查找规则:
1.在访问变量时先查找本地变量,然后是包裹此函数外部的函数内部的变量,之后是全局变量,最后是内置(内建)变量 L----> E ----> G -----> B
2.在默认情况下,变量名赋值会创建或者改变本地作用域变量;
global 语句:
作用:
1.告诉解释器,global语句声明的一个或多个变量,这些变量的作用域为模块级的作用域(也称作全局变量);
2.全局声明(global) 将赋值的变量映射到模块文件内部的作用域;
语法:syntax
global 变量1,变量2,....
示例见global.py
global 说明:
1.全局变量如果在函数内部被赋值,则必须经过全局声明(否则会被认为是局部变量);
2.全局变量在函数内部不经过声明就可以直接访问;
3.不能先创建局部变量,再用global声明为全局变量,此做法不附合规则;
4.global变量列表里的变量名,不能出现在此作用域内形参列表里(函数的形参列表里的变量名不能与global冲突);
nonlocal 语句:
作用:
告诉解释器,nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量;
nonlocal的语法:
nonlocal 变量名1,变量名2,....
示例见: nonlocal.py
nonlocal 说明 :
1.nonlocal 语句只能在被嵌套的函数内部进行使用;
2.访问nonlocal变量将对外部嵌套函数作用域内的变量进行操作;
3.当有两层或两层以上函数嵌套时,访问nonlocal变量只对最近一层的变量进行操作;
4.nonlocal语句的声明变量列表里的变量名,不能出现在此函数参数列表中;
def语句是用来创建函数的。
lambda 表达式(又称匿名函数):
作用:
创建一个匿名函数对象,同def类似,但不提供函数名;
语法格式:
lambda [形参1,形参2,...]:表达式
lambda 说明:
1.lambda 只是一个表达式,它用来创建一个函数对象;
2.当lambda表达式调用时,先执行冒号(:)后的表达式,并返回表达式的结果的引用;
3.lambda表达式创建的函数只能包含一条表达式,lambda比函数简单且可以随时创建和销毁,有利于减少程序的偶合度;
myadd = lambda a, b:[x for x in range(a,b)] myadd(5, 10) #[5,6,7,8,9] >>> fx = lambda a, b:(a ** 2 + 1) % b == 0 >>> fx(3,5) True mymax = lambda x , y: x if x > y else y
表达式,加减乘除是表达式,函数调用是表达式,if else 是条件表达式,推导式是表达式,lambda表达式;
==eval 和 exec 函数:
eval 函数:
作用:把一个字符串当成一个表达式来执行,返回表达式执行后的结果;
格式:
eval(source, globals=None, locals=None) 注意:变量访问作用域的优先级
示例见: eval.py x = 100 y = 200 v = eval('x + y') print(v) #300 dict_local = {'x':1 ,'y':2} v = eval('x + y', None, dict_local) print(v) #3 dict_global = {'x':10 ,'y':20} v = eval('x + y', dict_global, {'y':2}) print(v) #12 #注意变量访问优先级 v = eval('x + y', None, {'y':2}) print(v) #102
exec 函数:
作用:把一个字符串当成程序来执行;
格式:
exec(source, globals=None, locals=None)
示例见: exec.py # exec.py x = 100 y = 200 s = '''z = x + y print('z = ', z) print('hello world') ''' exec(s) #执行s这个字符串 print('z', z) #注意这里创建的变量z是全局 dict_local = {'x':1} exec(s,None, dict_local) print(dict_local) #变量z是函数内创建,是局部变量,在dict_local字典内
==函数式编程:
是指用一系列函数解决问题;
函数是一等公民(Guido):
1.函数可赋值给变量,赋值后变量绑定函数;
2.允许将函数本身作为参数传入另一个函数;
3.允许函数返回一个函数
函数好处:
用每一个函数完成细小的功能,一系列函数在任意组合可以完成大问题;
函数的可重入性:
当一个函数在运行时不读取和改变除局部作用域以外的变量时,此函数为可重入函数;
可重入函数在每次调用时,如果参数一定,则结果必然一定;
def mysum(n): return sum(range(n+1)) print(mysum(100)) 示例:可重入函数
高阶函数 high order function:
什么是高阶函数
满足下列条件中一个的函数即为高阶函数
1. 函数名可作为参数输入;
2. 函数名可作为返回值;
python中内建的高阶函数:
map, filter, sorted
map 函数:
map(func, *iterables) 用函数和对可迭代对象中的每一个元素作为参数返回新的可迭代对象,当最短的一个可迭代对象不再提供数据时迭代结束;
要求:
func函数接收的参数个数必须与可迭代对象的个数相同;
示例见: #map.py def power2(x): return x ** 2 #生成一个可迭代对象,此可迭代对象可以生成1-9的自然数的平方 for x in map(power2,range(1,10)): print(x, end=' ') #1 4 9 16 25 36 49 64 81 L1 = [1,2,3,4] L2 = [5,6,7,8] def power_x_y(x,y): return str(x) + 'or' + str(y) for x in map(power_x_y, L1, L2): print(x,end=' ') #1or5 2or6 3or7 4or8 # 3.求1**9 + 2 ** 8 + 3**7 +...9**1的和 #使用匿名函数解决 print('3.求两个迭代运算的和:', sum(map(lambda x, y: x ** y, range(1, 10), range(9, 0, -1))))
filter 函数:
格式:
filter(function, iterable)
作用:
筛选可迭代对象iterable中的数据,返回一个可迭代对象,此可迭代对象将对iterable提供的数据进行筛选;
说明 :
函数function将对iterable中的每个元素进行求布尔值,返回True则保留,返回False则丢弃;
函数名不写括号代替的是变量绑定的函数,函数写括号是让函数做事情返回结果;
示例见: filter.py #此函数判断x是否是奇数,如果是奇数返回True def isodd(x): return x % 2 == 1 for x in filter(isodd, range(41, 53)): print(x) #推导式中使用map,filter,lambda,range,for等 示例 print([x for x in map(lambda x: x ** 2, filter(isodd, range(41, 53)))]) [1681, 1849, 2025, 2209, 2401, 2601]
sorted 函数:
作用:
将原可迭代对象提供的数据进行排序,生成排序后的列表;
格式:
sorted(iterable, key=None, reverse=False)
说明:
iterable 可迭代对象;
key 函数是用来提供一个排序参考值的函数,这个函数的返回值将作为排序的依据;
reverse标志用来设置是否降序排序;
示例: L = [5, -2, -4, 0, 3, 1] L2 = sorted(L) #[-4, -2, 0, 1, 3, 5] #要得到这样的结果该怎么办? [0, 1, -2, 3, -4, 5] L3 = sorted(L, key=abs) #[0, 1, -2, 3, -4, 5] names = ['Tom', 'Jerry', 'Spike', 'Tyke'] names2 = sorted(names, key=len) print(names2) print(sorted(names, key=max)) print('sorted_names.py------------------') #sorted_names.py #练习: #已知: names = ['Tom', 'Jerry', 'Spike', 'Tyke'] #排序的依据为原字符串反序的字符串 # 思维 ’moT' yrreJ ekipS ekyT #结果: #['Spike', 'Tyke','Tom', 'Jerry' ] def get_key(n): #n用来绑定参数中每个元素 #此函数需要返回一个能比较大小的依据 print('get_key=', n) #将字符转换为列表,在反序,再转回字符串 L = list(n) L.reverse() return ''.join(L) print(sorted(names, key=get_key)) #方法二: def get_key(n): #n用来绑定参数中每个元素 #此函数需要返回一个能比较大小的依据 print('get_key=', n) return n[::-1] print(sorted(names, key=get_key)) # 方法三用匿名函数实现 print(sorted(names, key=lambda n: n[::-1]))
递归 函数:recursion
函数直接或间接的调用自身;
#示例: def f(): f() #直接调用自己,进入递归 f() #函数间接调用自身 def fa(): fb() def fb(): fa() fa() print('递归完成')
递归函数说明:
递归一定要控制递归的层数(默认最大1000层),当符合一定条件时要终止递归调用;
几乎所有的递归都用while循环来代替;
递归函数优点:
递归可以把问题简单化,让思路更为清晰,代码更简洁;
递归函数缺点:
递归因系统环境影响大,当递归深度太大时,可 会得到不可预知的结果;
递归的两个阶段:
递推阶段: 从原问题出发,按递归公式递推从未知到已知,最终达到递归的终止条件;
回归阶段: 按递归终止条件求结果,逆向逐步代入递归公式,回归到问题求解;
#recursion.py def fn(n): print('递归进入第', n, '层') #当递归进入第三层时,不再向下走,开始层层回归 if n == 5: return #结束函数,回到函数调用处 fn(n + 1) print('递归退出第', n, '层') fn(1) print('程序结束') -----执行结果----- 递归进入第 1 层 递归进入第 2 层 递归进入第 3 层 递归进入第 4 层 递归进入第 5 层 递归退出第 4 层 递归退出第 3 层 递归退出第 2 层 递归退出第 1 层 程序结束
递归的灾现方法:
先假设函数已经实现
""" 练习 1.已知: 第五个人比第四个人大2岁 第四个人比第三个人大2岁 第三个人比第二个人大2岁 第二个人比第一个人大2岁 第一个人说他10岁 编程算出第5个人几岁?思考是否可以使用递归和循环两种方式来做? """ #递归方法 def get_age(n): if n == 1: return 10 return 2 + get_age(n - 1) print('第五个人', get_age(10), '岁') #循环方法 def get_age1(n): z = 10 if n == 1: return z for x in range(1, n): z += 2 return z print('第五个人', get_age1(10), '岁') print('第1个人', get_age1(1), '岁') """ 2.已知有列表: L = [[3,5,8], 10, [[13,14], 15, 18], 20] a.写一个函数print_list(list)打印出列表内的所有元素,print_list(L) # 3 5 8 10 13 14... b. 写一个函数sum_list(lit): 返回这个列表中所有元素的和,print(sum_list(L)) #106 注:type()可以返回一个变量的类型 如:>>> type(20) is int #True >>> type([3,5,8]) is list #True 考虑递归和循环两种方式完成。 """ L = [[3,5,8], 10, [[13,14], 15, 18], 20] #a 打印所有的元素 #递归 def print_a(L): for x in L: if type(x) is int: print(x, end=' ') elif type(x) is list: print_a(x) #递归调用来处理内部列表 print_a(L) print() #循环 def show_list(L): for x in L: if type(x) is int: print(x, end=' ') elif type(x) is list: for y in x: if type(y) is int: # print('yyyyy') print(y, end=' ') elif type(y) is list: for k in y: if type(k) is int: # print('kkkkkk') print(k, end=' ') print('---------------') show_list(L,) print(end=' ') #b)递归 def sum_list(lst): s = 0 for x in lst: if type(x) is int: s += x elif type(x) is list: s += sum_list(x) #递归调用来处理内部列表 return s print('sum_list=', sum_list(L), end=' ') """ 3.改写之前的学生信息管理程序 要求添加四个功能: 5)按学生成绩高->低显示学生信息 6)按学生成绩低->高显示学生信息 7)按学生年龄高->低显示学生信息 8)按学生年龄低->高显示学生信息 """ #定义添加学生信息函数 def input_student(): lst = [] #定义空列表 #定义循环读入学生信息 while True: student_name = input('请输入学生姓名:') #判断输入学生姓名为空结束输入 if not student_name: break student_age = int(input('请输入学生年龄:')) student_score = int(input('请输入学生成绩:')) student_dict = {} #定义新空字典,用于存放学生信息 student_dict['name'] = student_name student_dict['age'] = student_age student_dict['score'] = student_score #将字典使用append方法,存入到L列表中,注意这此处未改变L全局变量的绑定关系 lst.append(student_dict) #print('打印列表lst信息: ',lst) return lst #定义显示学生信息函数 def output_student(L): #显示学生信息列标头 print('+','-' * 20,'+','-' * 10,'+','-' * 12, '+') print('|', 'name'.center(20),'|','age'.center(10), '|', 'score'.center(12), '|') print('+','-' * 20,'+','-' * 10,'+','-' * 12, '+') #此处打印所有学生的信息 #把学生的数据取出来,用k绑定对应的字典 for k in L: #将姓名格式变成20宽度居中的字符串 center_name = k['name'].center(22) #先将年龄转换为字符串 str_age = str(k['age']) center_age = str_age.center(12) str_score = str(k['score']) center_score = str_score.center(14) #print('|',center_name, '|', center_age, '|', center_score, '|') line = "|%s|%s|%s|" % (center_name, center_age, center_score) print(line) print('+','-' * 20,'+','-' * 10,'+','-' * 12, '+') #定义删除学生信息函数,注意带入的参数 def delete_student(Lst): namevalue = input('请输入需要删除学生姓名:') for i in range(len(Lst)): if namevalue == Lst[i]['name']: del Lst[i] break output_student(Lst) def modify_student(): pass #定义根据学生成绩高到低排序显示 def score_hightolow(lst): def get_key(lst): return lst['score'] output_student((sorted(lst, key=get_key, reverse=True))) #定义根据学生成绩低到高排序显示,匿名函数实现 def score_lowtohigh(lst): output_student((sorted(lst, key=lambda d:d['score'], reverse=False))) #定义根据学生年龄高到低排序显示 def age_hightolow(lst): def get_key(lst): return lst['age'] output_student((sorted(lst, key=get_key, reverse=True))) #定义根据学生年龄低到高排序显示,匿名函数实现 def age_lowtohigh(lst): output_student((sorted(lst, key=lambda d: d['age'], reverse=False))) #定义学生信息菜单 def show_menu(): print('+' + '-' * 48 + '+') print('+' + '1) 添加学生信息'.ljust(42) + '+') print('+' + '2) 显示学生信息'.ljust(42) + '+') print('+' + '3) 删除学生信息'.ljust(42) + '+') print('+' + '4) 修改学生信息'.ljust(42) + '+') print('+' + '5) 按学生成绩高to低显示学生信息'.ljust(35) + '+') print('+' + '6) 按学生成绩低to高显示学生信息'.ljust(35) + '+') print('+' + '7) 按学生年龄高to低显示学生信息'.ljust(35) + '+') print('+' + '8) 按学生年龄低to高显示学生信息'.ljust(35) + '+') print('+' + '9) 退出应用程序'.ljust(42) + '+') print('+' + '-' * 48 + '+') n = int(input('请选择:') or '-1') return n #定义主函数 def main(): docs = [] while True: n = show_menu() if n < 0: print('请输入正确的菜单选项') break else: if n == 1: docs += input_student() elif n == 2: output_student(docs) elif n == 3: delete_student(docs) elif n == 4: modify_student() elif n == 5: score_hightolow(docs) elif n == 6: score_lowtohigh(docs) elif n == 7: age_hightolow(docs) elif n == 8: age_lowtohigh(docs) elif n == 9: break print(' 4.------------- ') main()