目录:
python作用域 、lambda表达式(又称匿名函数) 、 函数式编程 、 递归函数 recursion
python作用域:
定义:
作用域也叫命名空间,是访问变量时查找变量名的范围空间python的四个作用域LEGB
作用域 英文解释 英文简写 局部作用域(函数内) Local(function) L 外部嵌套函数作用域 Enclosing function locals E 函数定义所在模块的作用域 Global(module) G python 内置模块的作用域 Builtin(python) B 示例见:
v = 100 # 全局变量 def fun1(): v = 200 print('fun1里的v的值是: ', v) # 定义另一个函数 fun2,然后调用一个 def fun2(): v = 300 print('fun2里的v=', v) fun2() fun1() print('全局的 v=', v)
- 变量名的查找规则(顺序):
- 查找本地变量
- 查找包裹此函数的外部嵌套函数内部的变量
- 全局变量
- 内置变量
globals() / locals() 函数
- 作用:
globals() 返回全局作用内变量的字典
locals() 返回局部作用域内变量的字典 示例见:
# 此示例示意globals 和 locals 函数的用法 a = 100 b = 200 def fx(b, c): print(a, b, c) # 思考在此函数内部能否获取到全局变量b绑定的值? print("全局变量的字典是:", globals()) print("局部变量的字典是:", locals()) print("此处访问全局的b的值是:", globals()['b']) fx(300, 400)
练习:
写一个函数 mysum 此函数的功能是返回:
1 + 2 + 3 + 4 + 5 + ….. + n 的和
def mysum(n):
….print(mysum(100)) # 5050
写一个函数 mysum2 此函数可以传入一个参数,两个参数和三个参数:
- 当传入一个参数时,这个参数代表 终止数
- 当传入两个参数时,第一个参数代表起始值,第二个参数代表终止值
- 当传入三个参数时,第三个参数代表步长
此函数的功能是返回从开始到终止值的和
如:
print(mysum2(5)) # 10 (0+1+2+3+4)
print(mysum2(4, 6)) # 9 (4+5)
print(mysum2(5, 10, 2)) # 21 (5+7+9)
global 语句
- 作用:
1. 告诉解释执行器,global语句声明的一个或多个变量,这些变量的作用域为模块级的作用域的变量,也称作全局变量
2. 全局声明(global) 将赋值变量映射到模块文件内部的作用域 - 语法:
global 变量1, 变量2, … - 示例:
global ga, gb
global gc
global声明示例见:
global_statement.py - 说明:
1. 全局变量如果要在函数内部被赋值,则必须经过全局声明(否则会被认为是局部变量)
2. 全局变量在函数内部不经过声明就可以直接访问
3. 不能先声明局部变量,再用global声明为全局变量,此做法不附合规则
4. global变量列表里的变量名不能出现在此作用域内的形参列表里
nonlocal语句
- 作用:
告诉解释器, nonloca声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量 - 语法:
nonlocal 变量名1, 变量名2, …. 示例见:
``` # 此示例示意nonlocal语句的作用 v = 100 def outter(): v = 200 print("outter里的v=", v) # 在函数内创建一个函数并调用 def inner(): nonlocal v # 声明v为外部嵌套函数的作用域内的变量 v += 1 print("innter里的v=", v) inner() # 调用上面的函数 print('调用inner后,outter里的v=', v) outter() print("全局里的v的值是:", v) ```
说明:
1. nonlocal语句只能在被嵌套函数内部进行使用
2. 访问nonlocal变量将对外部嵌套函数作用域内的变量进行操作
3. 当有两层或两层以上函数嵌套时,访问nonlocal变量只对最近一层的变量进行操作
4. nonlocal语句的变量列表的变量名不能出现在此函数的参数列表里示例:
def f1():
v =100
def f2():
v = 200
def f3():
nonlocal v
v += 1 # 此时只对f2的v进行操作
f3()
f2()练习:
创建一个列表L = []
写一个函数 input_number读取数据放入列表L中
程序如下:
L = []
def input_number():
# 此处自己加入代码
while True:
i = int(input(“请输入数字(-1结束):”))
# 此处自己完成
input_number()
print(“您刚才输入的整数值是:”, L)写一个函数isprime(x) 判断x是否为素数,如果为素数返回True,否则返回False
测试代码:
if isprime(5):
print(“5素数”)写一个函数prime_m2n(m, n) 返回从m开始,到n结束范围内素数的列表,并打印
L = prime_m2n(10, 20)
print(L) # [11, 13, 17, 19]写一个函数primes(n), 返回小于n的所有的素数的列表.
L = primes(10)
print(L) # [2, 3, 5, 7]
lambda 表达式(又名匿名函数表达式)
作用:
创建一个匿名函数对象
同def类似,但不提供函数名
语法:
lambda [形参1, 形参2, ...] : 表达式
示例:
def myadd(x, y):
return x + y
可以改写为:
myadd = lambda x, y: x + y
print(myadd(100, 200))
print(myadd("ABC", "100"))
语法说明:
1. lambda 只是一个表达式,它用来创建一个函数对象
2. 当lambda表达式调用时,先执行冒号后的表达式,并返回表达式的结果的引用
3. lambda 表达式创建的函数只能包含一条表达式
4. lambda比函数简单,且可以随时创建和销毁,有利于减少程序的偶合度
练习:
- 写一个lambda表达式, 判断这个数的2次方+1 能否被5整数,如果能整除返回True, 否则返回False
fx = lambda n: .......
print(fx(4)) # False
print(fx(3)) # True 写一个lambda 表达式,求两个变量的最大值:
mymax = lambda ...
print(mymax(55, 63)) # 63看懂下面的程序在做什么:
def fx(f, x, y): r = f(x, y) print(r) fx((lambda a, b: a + b), 100, 200) fx((lambda x, y: x ** y), 3, 4)
eval函数:
作用:
把一个字符串当成一个表达式执行,返回表达式执行后的结果
格式:
`eval(source, globals=None, locals=None)`
示例:
```
x = 100
y = 200
s = "x+y"
v = eval(s)
print(a)
print(eval("x+y", {'x':10, 'y':20})) # 30
print(eval("x+y", {'x':10, 'y':20}, {'x':1, 'y':2})) # 3
print(eval("x+y", {'x':10, 'y':20}, {'x':1})) # 21
```
exec函数:
作用:
把一个字符串当成程序来执行
格式:
exec(source, globals=None, local=None)
示例:
s = 'x=100; print("hello"); x += 1; print(x)'
print(s)
exec(s)
示例:
自己写一个程序,解释执行用户输入的任何语句:
```
# 自己写一个程序,解释执行用户输入的任何语句:
g = {}
l = {}
while True:
s = input("请输入语句 $ >>>> ")
if s == "bye":
break
exec(s, g, l)
print(g)
print(l)
```
函数式编程:
定义:
是指用一系列函数解决问题
函数是一等公民
- 函数本身是对象,可以赋值给变量,赋值后变量绑定函数
- 允许将函数作为实参传入另一个函数
- 允许函数返回一个函数
函数式编程的好处:
- 每一个函数完成细小的功能,一系列函数的任意组合可以解决大的问题
- 函数仅接收输入并产生输入,不会影响其它全局变量的状态
思考:
求 1+ 2 + 3 + …… + n 的和
print(sum(range(n+1)))
练习:
求: 1 + 1/2 + 1/4 + 1/8 + … + 1/2**n
n = 100
print(sum([1/2**x for x in range(n + 1)]))
高阶函数 High Order Function
什么是高阶函数:
满足下列条件中的一个的函数即为高阶函数
1. 函数接受一个或多个函数作为参数传入
2. 函数返回一个函数
python内置(builtins)的高阶函数:
map 函数:
map(func, *iterables) 用函数对可迭代对象中的每一个元素作为参数计算出新的可迭代对象,当最短的一个可迭代对象不再提供数据时,此可迭代对象生成结束
示例 :
# 生成一个可迭代对象,要求此可迭代对象可以生成1~9自然数的平方 1, 4, 9, 16, .... 81 def power2(x): return x**2 for x in map(power2, range(1, 10)): print(x) # 求以上数据的和 1 + 4 + 9 + 16 + ... + 81 print(sum(map(power2, range(1, 10))))
示例:
# 生成一个可迭代对象, 要求此可迭代对象生成 # 1**4, 2**3, 3**2, 4**1 # 1 8 9 4 for x in map(pow, [1,2,3,4], [4,3,2,1]): print(x)
练习:
1. 求 1**2 + 2**2 + 3**2 + ... 9**2的和 def f2(x): return x ** 2 s = sum(map(f2, range(1, 10))) print(s) # 方法2 print(sum(map(lambda x: x**2, range(1, 10)))) 2. 求 1**3 + 2**3 + 3**3 + ... 9**3的和 print(sum(map(lambda x: x**3, range(1, 10)))) 3. 求 1**9 + 2**8 + 3**7 + ... 9**1的和 print(sum(map(pow, range(1, 10), range(9, 0, -1))))
filter函数:
- 格式:
filter(func, iterable) 作用:
筛选可迭代对象iterable中的数据,返回一个可迭代对象,此可迭代对象将对iterable进行筛选
函数func 将对iterable中的每个元素进行求值,返回False时将此数据丢弃,返回True,则保留此数据示例:
# isodd函数判断x是否为奇数,是奇数返回True def isodd(x): return x % 2 == 1 # 打印10以内的奇数: for x in filter(isodd, range(10)): print(x) # 生成10以内所有偶数的列表,用filter实现 L = [x for x in filter(lambda x: x%2==0, range(10))]
- 格式:
sorted 函数:
- 作用:
将原可迭代对象的数据进行排序,生成排序后的列表 - 格式:
sorted(iterable, key=None, reverse=False)
- 参数说明:
iterable 可迭代对象
key 绑定函数,此函数用来提供一个排序的依据
reverse 标志用来设置是否降序排序(从大到小) 示例:
L = [5, -2, -4, 0, 3, 1] L2 = sorted(L) # L2 = [-4, -2, 0, 1, 3, 5] L3 = sorted(L, reverse=True) L3=[5,3,1...] L = [5, -2, -4, 0, 3, 1] # 依据: abs(5), abs(-2), abs(-4), abs(0), ... L4 = sorted(L, key=abs) # L4 =[0, 1, -2, 3, -4, 5] names = ['Tom', 'Jerry', 'Spike', 'Tyke'] L = sorted(names) # L = ['Jerry', 'Spike', 'Tom', 'Tyke'] # 能否根据名字的长度进行排序? L2 = sorted(names, key=len) # L2 = ['Tom', 'Tyke', 'Jerry', 'Spike'] def fr(s): return s[::-1] L3 = sorted(names, key=fr)
- 作用:
递归函数 recursion
定义
函数直接或间接的调用自身示例:
# 直接调用自身 def f(): f() # 调用自己 f() print("递归完成") # 函数间接调用自身 def fa(): fb() def fb(): fa() fa()
- 递归说明:
递归一定要控制递归的层数,当符合某一条件时要终止递归
几乎所有的递归都能用循环来代替 递归的优缺点:
- 优点:
递归可以把问题简单化,让路径更为清晰,代码更为简洁 - 缺点:
递归因系统环境影响大,当递归深度太大时,可以会得到不可预知的结果
- 优点:
示例:
def story(): print("从前有座山,山上有座庙,庙里有个老和尚讲故事: ") stroy() print("故事请讲完了")
- 递归说明:
递归函数的实现方法:
先假设函数已经实现示例:
求:100 + 99 + 98 + 97 + ..... + 1 的和 分析: 先假设 mysum(x) 已经完成,且能求 x + (x-1) + .. +1的和 def mysum(x): # 选判断终止条件 if x == 1: return 1 return x + mysum(x - 1) print(mysum(100)) # 5050
练习:
- 编写函数 myfac(x) 计算x的阶乘x!
5! = 5 * 4 * 3 * 2 * 1
print(myfac(5)) # 120
写程序算出1~20的阶乘的和
1! + 2! + 3! + …. + 19! + 20!
思考:
能否用函数式编程中的高阶函数实现?已知有列表:
L = [[3,5,8], 10, [[13, 14], 15], 18]
1) 写一个函数 print_list(lst) 打印出列表中所有数字
print_list(L)
2) 写一个函数sum_list(lst) 返回列表中所有数字的和
print(sum_list(L)) # 86
注:
type(x) 可以返回一个变量的类型
如:
>>> type(20) is int # True
>>> type([1,2,3]) is list # True
开始学生信息管理项目
需要两个函数:
input_student() 返回学生信息的字典的列表
output_student(lst) 以表格式方打印学生信息
学生信息:
姓名(name) 字符串
年龄(age) 整数
成绩(score) 整数
input_student() 调用时等待用户输入学生信息,当输入姓名为空时结束输入,最后将学生信息形成字典后存如列表中返回
def input_student():
….L = input_student()
请输入学生姓名: xiaozhang
请输入学生年龄: 20
请输入学生成绩: 98
请输入学生姓名: xiaoli
请输入学生年龄: 23
请输入学生成绩: 100
请输入学生姓名: <回车>输入结束
此时列表数据为:
L = [{‘name’:’xiaozhang’,
‘age’:20,
‘score’: 98},
{‘name’:’xiaoli’,
‘age’:23,
‘score’: 100}
]
def output_student(lst):
…print(L) # 打印出字典的列表
output_student(L) # 打印出学生信息的表格如下:
+———–+——–+———+
| name | age | score |
+———–+——–+———+
| xiaozhang | 20 | 98 |
| xiaoli | 23 | 100 |
+———–+——–+———+- 编写函数 myfac(x) 计算x的阶乘x!
闭包 closure
- 定义:
将内嵌函数的语句和这些语句的执行环境打包在一起后,得到的函数对象称为闭包(closure) - 闭包必须满足以下三个条件:
- 必须有一个内嵌函数
- 内嵌函数必须引用外部函数中的变量
- 外部函数返回值必须是内嵌函数
示例:
#此程序示意闭包的用法 #1. fn为内嵌函数 #2. fn 用到了fn外部的变量y #3. make_power将 fn绑定的函数对象返回给调用者 def make_power(y): def fn(x): return x ** y return fn pow2 = make_power(2) #pow2 等同于: # def pow2(x): # return x ** 2 print("5的平方是:", pow2(5)) # 25 print("9的平方是:", pow2(9)) # 81 # def pow4(x): # return x**4 pow4 = make_power(4) print('5的四次方是:', pow4(5))
- 说明:
如果一个内嵌函数访问了外部嵌套函数作用域内的变量,则这个内嵌函数就是闭包
- 说明:
装饰器 decorators(专业提高篇)
什么是装饰器:
装饰器是一个函数,这个函数的主要作用是包装别一个函数或类(后在才讲)
包装的目的是在不改变原函数名的情况下改变被包装对象的行为
函数装饰器 function decorators
函数装饰器是指装饰器是一个函数,传入的是一个函数,返回的也是一个函数
示例:
def mydeco(fn): # <<==装饰器函数
def fx():
print("hello world!")
return fx
@mydeco
def hello(): # <<== 被装饰函数
print("hello home!")
# 此时将hello 变量绑定在了mydeco返回的函数上
# hello = mydeco(hello) # 此种做法可以用装饰器@语法解决
hello() # 调用者
def mydeco(fn): # <<==装饰器函数
def fx():
print("++++++++++++")
fn()
print('------------')
return fx
# @mydeco
def hello(): # <<== 被装饰函数
print("hello home!")
hello() # 调用者
# deco3.py
# 本示例示意带有参数的装饰器及其用法
# 以下是一个装饰器函数,在fn调用之前加一个权限验证的功能
def priv_check(fn):
def fx(name, x):
print("正在权限验证...")
fn(name, x)
return fx
# 存钱对应的函数
@priv_check
def save_money(name, x):
print(name, "存钱", x, "元")
# 取钱对应的函数
@priv_check
def withdraw(name, x):
print(name, "正在办理取钱", x, '元的业务')
# 小郭程序员
save_money("小张", 200)
save_money("小赵", 500)
withdraw("小李", 300)
# deco3.py
# 本示例示意一个函数可以使用两个或两个以上的装饰器来装饰
# 以下是一个装饰器函数,在fn调用之前加一个权限验证的功能
def priv_check(fn):
def fx(name, x):
print("正在权限验证...")
fn(name, x)
return fx
def message_send(fn):
def fy(name, x):
# 先办其它业务
fn(name, x)
print("短信: ", name, "发生了", x, "元的操作,余额是xxx")
return fy
# 存钱对应的函数
@priv_check
def save_money(name, x):
print(name, "存钱", x, "元")
# 取钱对应的函数
@message_send
@priv_check
def withdraw(name, x):
print(name, "正在办理取钱", x, '元的业务')
# 小郭程序员
save_money("小张", 200)
save_money("小赵", 500)
withdraw("小李", 300)
函数的文档字符串:
语法:
def 函数名(参数列表):
"""函数的文档字符串"""
函数语句块
说明:
文档字符串通常来用说明本函数的功能和使用方法
在交互模式下,输入help(函数名) 可以查看函数的”文档字符串”
函数的doc属性:
- 定义:
函数内第一次末赋值给任何变量的字符串是此函数的文档字符串
此字符串会自动赋值给函数的doc属性 - 示例:
def cba():
'这是一个文档字符串'
pass
print(cba.__doc__) # 这是一个文档字符串
函数定义语句的完整语法:
[@装饰器1]
[@装饰器2]
[...]
def 函数名([位置形参], [*元组形参], [命名关键字形参],
[**字典形参]):
"文档字符串"
语句块