文章目录
1 函数基础
函数可以看成是语句的集合,通过函数调用来执行其包含的语句。函数可以返回一个计算结果,根据每次函数调用的参数,可以返回不同的结果。Python利用函数提高代码的重用率,较少了代码冗余
函数也是一个对象
1.1 定义函数
- Python使用 def 语句来定义函数:
def 函数名(参数表):
函数语句
return 返回值
注意:
函数名必须符合标识符的规范(可以包含字母、数字、下划线但是不能以数字开头)
- 参数和返回值都不是必须有的,Python允许函数没有参数和返回值。
>>> def hello(): #定义函数
print("Pyhon 你好")
>>> hello() #调用函数
Pyhon 你好
- 下面的例子为函数定义两个参数,并用return语句得到返回值
>>> def add(a,b):
return a+b
>>> add(1,3)
4
1.2 函数调用
- 函数通过函数名加上一组圆括号进行调用(未加圆括号则为调用函数对象)
- 在Python中,函数名也是一个变量,它引用
return
语句返回的值,没有返回值时,默认函数值为 None
>>> def add(a,b):
return a+b
>>> add #直接用函数名,可返回函数名变量的内存地址
<function add at 0x03719300>
>>> add(10,20)
30
>>> x=add #将函数名赋值给变量
>>> x(1,2) #通过变量调用函数
3
1.3 函数参数
1.3.1 形参和实参
- 在定义函数时,参数表中的各个参数称为形式参数,简称形参
- 在调用函数时,参数表中提供的参数称为实际参数,简称实参
- 变量保存的是对象的引用,类似C/C++这的指针
- 实参传递给形参就是将对象的引用赋值给形参
1.3.2 函数的传递方式
- 定义形参时,可以为形参指定默认值。指定了默认值以后,如果用户传递了参数则默认值不会生效。如果用户没有传递,则默认值就会生效
def add(a,b):
return a+b
if __name__ == '__main__':
a = 3 # 设置默认值
result = add(4,5) # 传递参数,默认值失效
print(result) # 9
result_1 = add(a,4) # 为覆盖参数,使用默认值
print(result_1) # 7
- 位置参数:位置参数就是将对应位置的实参赋值给对应位置的形参
def number(a,b):
return a,b
if __name__ == '__main__':
result = number(3,4) # (3,4)
result_1 = number(4,3) # (4,3)
print(result)
print(result_1)
- 关键字参数 : 关键字参数可以不按照形参定义的顺序去传递,而根据参数名进行传递
def reduce(a,b):
return a-b
if __name__ == '__main__':
print(reduce(a=4,b=2)) # 2
print(reduce(b=4,a=2)) # -2
- 混合使用位置参数和关键字参数的时候必须将位置参数写到关键字参数前面去
1.3.3 不定长参数
- 定义函数时,可以在形参前面加一个*,这样这个形参可以获取到所有的实参,它会将所有的实参保存到一个元组中
- 带*号的形参只能有一个,可以和其他参数配合使用
- *形参只能接受位置参数,不能接受关键字参数
def add(a,*b,c=23):
s = a
for i in b:
s += i
return s,c
if __name__ == '__main__':
print(add(1,2,3,4,5)) #15
带星号的参数之后的参数必须通过赋值传递
- **形参可以接收其他的关键字参数,它会将这些参数统一保存到字典当中。字典的key就是参数的名字,字典的value就是参数的值
- **形参只有一个,并且必须写在所有参数的后面
- * 处理的是位置参数,** 处理的是关键字参数
1.3.4 参数的解包
def unpack(a,b,*c):
print(a)
print(b)
print(c)
def unpack_dict(a,b,**c): #关键字
print(a)
print(b)
print(c)
if __name__ == '__main__':
lis = [1,2,3,4,5]
tup = (6,7,8,9)
d = {'a':10,'b':11,'c':12,'d':13,'e':14}
unpack(*lis)
unpack(*tup)
unpack_dict(**d)
'''
1
2
(3, 4, 5)
6
7
(8, 9)
10
11
{'c': 12, 'd': 13, 'e': 14}'''
1.4 函数嵌套定义
- Python允许在函数内部定义函数。
def add(a,b):
def getsum(x):
s=0
for n in x:
s+=ord(n)
return s
return getsum(a)+getsum(b)
if __name__ == '__main__':
result = add('12','34')
print(result)
'''
ord(1) --> 49
2 50
3 51
4 52
202
'''
1.5 lambda函数
- lambda 函数也称表达式函数,用于定义一个匿名函数,可将该函数赋值给变量,通过变量调用。
- 格式:
lambda 参数表:表达式
result = lambda a,b:a+b
print(result(6,4)) # 10
1.6 递归函数
- 指在函数体内调用函数本身
- 递归式的函数有两个条件
- 基线条件:问题可以被分解成为最小的问题,当满足基线条件时,递归不再执行
- 递归条件:问题可以继续分解的条件
1.6.1 阶乘计算
def factorial(n):
result = n
if n==0:
return 1
return result*factorial(n-1)
if __name__ == '__main__':
n = int(input("请输入你要计算阶乘的数:"))
while n!=0:
print(factorial(n))
n = int(input("请输入你要计算阶乘的数:"))
print("程序结束!")
'''
请输入你要计算阶乘的数:2
2
请输入你要计算阶乘的数:3
6
请输入你要计算阶乘的数:4
24
请输入你要计算阶乘的数:5
120
请输入你要计算阶乘的数:0
程序结束!
Process finished with exit code 0
'''
1.7 函数列表
- Python 允许将函数作为列表
>>> d = [lambda a,b:a+b,lambda a,b:a*b]
>>> d[0](2,5)
7
>>> d[1](2,5)
10
- 也可以使用def定义的函数来创建
>>> def add(a,b):
return a+b
>>> def factorial(n):
if n==0:
return 1
else:
return n*factorial(n-1)
>>> d=[add,factorial] #建立函数列表
>>> d[0](2,3)
5
>>> d[1](5)
120
>>> d=(add,factorial) #建立函数元组
>>> d[0](1,2)
3
>>> d[1](4)
24
>>> d={'求和':add,'求阶乘':factorial} #建立函数映射
>>> d['求和'](3,4)
7
>>> d['求阶乘'](6)
720
2 变量作用域
- 作用域指的是变量生效的区域
2.1 有哪些作用域
- 1-内置作用域
- 2-文件作用域
- 3-函数嵌套作用域
- 4-本地作用域
- 作用域依次减小
全局作用域 | 函数作用域 |
---|---|
1、2 | 3、4 |
程序执行时创建,在程序执行结束时销毁 | 在函数调用时创建,在调用结束时销毁 |
所有函数以外的区域都是全局作用域 | 函数每调用一次就会产生一个新的函数作用域 |
在全局作用域中定义的变量,都是全局变量,全局变量可以在程序的任意位置进行访问 | 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问 |
a=10 # a是全局变量
def add(b): #参数b是函数内的本地变量
c = a + b # c是函数内的本地变量,a 是函数外的全局变量
return c
- 作用域内的变量与作用域外的变量名称相同时,遵循本地优先原则,此时外部的作用域被屏蔽——称为作用域隔离原则
>>> a = 10 # 创建全局变量 a
>>> def show_1():
a=100 # 创建本地变量 a
print('in show_1 a=',a)
>>> show_1()
in show_1 a= 100 # 本地变量屏蔽了全局变量
- 将上面代码稍作修改
>>> a = 10
>>> def show():
print('a=',a)
a=100
print('a=',a)
>>> show()
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
show()
File "<pyshell#5>", line 2, in show
print('a=',a)
UnboundLocalError: local variable 'a' referenced before assignment
- 调用函数时,因为后面有赋值语句,即将根据本地优先原则,即函数内 a 的值才是本地变量,又因变量的作用域,先打印 a 的值,会报错,提示本地变量 a 使用之前没有赋值。
2.2 global 语句
- 全局变量不经定义即可在函数内部使用。
- 当在函数内部给变量赋值时,该变量将被Python视为局部变量
- 为了在函数内部给全局变量赋值,Python 提供了global 语句,用于在函数内部声明全局变量
>>>a = 10
>>>def show():
global a #声明 a 是函数外部的一个全局变量
print('a=',a)
a = 100
print('a=',a)
>>>show()
a=10
a=100
>>>a
100
- 因为在函数内部使用了 global 语句进行声明,所以代码中使用到的 a 都是全局变量
2.3 nonlocal 语句
- 如果要在嵌套函数内部修改外部本地变量,Python提供了nonlocal 语句。nonlocal 语句与global语句类似,他声明变量是外部的本地变量
>>> def test():
a=10
def show():
nonlocal a # 声明 a 是test函数的本地变量 a
a=100
print('in show a=',a)
show()
print('in test a=',a)
>>> test()
in show a= 100
in test a= 100
2.4 命名空间
- 命名空间实际上就是一个字典,是一个专门用来存储变量的字典
- locals()用来获取当前作用域的命名空间
- 如果在全局作用域中调用locals()则获取全局命名空间,
- 如果在函数作用域中调用locals()则获取函数命名空间
- 返回值是一个字典
def fun():
a = 100
if a >=60:
c = a - 60
return c
if __name__ == '__main__':
a = 48
result = fun()
s = locals()
s['b'] = result + a
print(s)
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0156DCF0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/Python_Space/basic_python/函数/命名空间.py', '__cached__': None, 'fun': <function fun at 0x015A9420>, 'a': 48, 'result': 40, 's': {...}, 'b': 88}
3 编程实践
3.1 实现杨辉三角
杨辉三角:第一列和主对角上的数字均为1,其他位置上的数字为 “上一行前一列” + “上一行同一列” 的结果
class Yh:
def __init__(self,num): # 参数 num 即为要输出杨辉三角的阶数
self.basenumber = num
def data_list(self):
base_lis = [[1]*i for i in range(1,self.basenumber+1)]
for i in range(2,len(base_lis)):
for j in range(1,len(base_lis[i])-1):
base_lis[i][j] = base_lis[i-1][j-1] + base_lis[i-1][j]
return base_lis
def main(self):
list_result = self.data_list()
for i in range(len(list_result)):
print(" "*(len(list_result)-i),end='') # “ ”里面的空格视输出美观而定
for j in range(len(list_result[i])):
print('%-8d'%list_result[i][j],end='')
print()
if __name__ == '__main__':
num = int(input("请输入您要观察的杨辉三角阶数:"))
while num>2:
R = Yh(num)
R.main()
num = int(input("请输入您要观察的杨辉三角阶数:"))
print("您输入的阶数不符合实际,程序结束!")
3.2 实现汉诺塔 模拟函数
汉诺塔:它是一个经典的递归问题,可将移动 n 片金片的步骤归纳如下:
第一步:将A针上的n-1片金片通过C针的帮助,移动到B针
第二步:将A针剩余的一片金片移到C针
第三步:重复第一步,将B针的n-1片金片通过A针的帮助,移动到C针
def hnt(list,a,b,c):
global count
n = len(list) # 每一次递归都要重新读取列表的长度
if n == 1:
count += 1
print('%-8d'%count,list[0],':',a,'----->',c)#nlist[0]即为最上面可以移动的值
else:
hnt(list[:n-1],a,c,b)#第一步:A针倒数第二片,移到B针
hnt([list[-1]],a,b,c)#第二步:A针最后一片移到C针
hnt(list[:n-1],b,a,c)#第三步:B针的倒数第二片通过A针移到C针
if __name__ == '__main__':
count = 0
n = int(input("请输入A针上原始金片数量:"))
while n > 2:
list = [_ for _ in range(n)]
hnt(list,'A','B','C')
n = int(input("请输入A针上原始金片数量:"))
print("程序结束!")
4 习题
4.1 lambda最大值
请输入第一个整数: a
请输入第二个整数: b
请输入第三个整数: c
其中的最大值为: maxnumber
a = int(input("请输入第一个整数:"))
b = int(input("请输入第二个整数:"))
c = int(input("请输入第三个整数:"))
maxnumber = lambda a,b,c:max(a,b,c)
print("其中的最大值为:",maxnumber(a,b,c))
4.2 斐波拉契数列
斐波拉契数列,又称黄金分割数列,以兔子繁殖为例引入,故又称”兔子数列“
请定义一个函数返回斐波拉契数列的第 n 项,并输出斐波拉契数列的卡10列
def febla(n):
if n==1 or n==2:
return 1
else:
return febla(n-1) + febla(n-2)
if __name__ == '__main__':
n = int(input("请输入您想要得到的斐波拉契数的阶数:"))
for i in range(1,n+1):
print(febla(i),end=' ')