【python基础语法五】python函数和函数相关概念

函数

含义

  • 概念:功能 (包裹一部分代码 实现某一个功能 达成某一个目的)
  • 特点:可以反复调用,提高代码的复用性,提高开发效率,便于维护管理

函数基本格式

"""
# 定义一个函数
def 函数名():
	code1
	code 
	
# 调用函数
函数名()
"""
# 定义函数
def func():
	print("我是一个函数 ... ")

# 调用函数
func()

函数的命名

"""
字母数字下划线,首字符不能为数字
严格区分大小写,且不能使用关键字
函数命名有意义,且不能使用中文哦

驼峰命名法:
	(1) 大驼峰命名法: 每个单词的首字符要大写 (类的命名)
		mycar => MyCar
	(2) 小驼峰命名法: 除了第一个单词首字符小写外,剩下单词首字符大写 (函数或者变量)
		mycar => myCar
_命名法:可以将不同的单词用_拼接在一起
	mycar => my_car
	symmetric_differencesymmetricDifference SymmetricDifference
"""

# 函数定义
def cfb_99():
	for i in range(1,10):
		for j in range(1,i+1):
			print("{:d}*{:d}={:2d} ".format(i,j,i*j) ,end="")
		print()
# 调用函数
for i in range(5):
	cfb_99()

函数参数

"""
参数: 函数运算时需要的值

参数种类:
	(1)形参: 形式参数,在函数的定义处
	(2)实参: 实际参数,在函数的调用处

形参的种类:
	1.普通形参(位置形参) 2.默认形参 3普通收集形参 4.命名关键字形参 5.关键字收集形参
实参的种类:
	1.普通实参 2.关键字实参
	
原则:
	形参和实参要一一的对应
"""

1.普通形参(位置形参)

# 定义函数
"""hang,lie普通形参,在函数定义处"""
def small_star(hang,lie):
	i = 0
	while i < hang:
		j = 0
		while j < lie:
			print("*",end="")
			j +=1
		print()
		i += 1
# 调用函数
"""10,10普通实参,在函数的调用处"""
small_star(10,10)
small_star(2,3)

2.默认形参

"""hang,lie默认形参,在函数定义处"""
"""
如果给予实参,那么使用实参
如果没有给予实参,那么使用参数身上的默认值
"""
def small_star(hang=10,lie=10):
	i = 0
	while i < hang:
		j = 0
		while j < lie:
			print("*",end="")
			j +=1
		print()
		i += 1

small_star(4,8)
small_star(8)
small_star()

3.普通形参 + 默认形参

"""普通形参必须写在默认形参的前面不能调换位置"""
def small_star(hang,lie=10):
	i = 0
	while i < hang:
		j = 0
		while j < lie:
			print("*",end="")
			j +=1
		print()
		i += 1
small_star(5,7)
# small_star(5)
# small_star() # error

4.关键字实参

"""
1.如果都是关键字实参,可以任意调整实参的顺序
2.普通实参必须写在关键字实参的前面
"""
def small_star(hang,a,b,c,lie=10):
	i = 0
	while i < hang:
		j = 0
		while j < lie:
			print("*",end="")
			j +=1
		print()
		i += 1

# hang a ... lie 具体指定参数的值叫做关键字实参,在函数的调用处;
# small_star(hang=3,a=4,b=5,c=6,lie=7)
# small_star(b=5,c=6,lie=7,a=4,hang=3)
small_star(3,4,b=5,c=6,lie=7)
small_star(3,4,b=5,lie=7,c=6)
# small_star(b=5,c=6,lie=7,3,4) # error

函数的收集参数

(1) 普通收集形参

"""
普通收集形参: 专门用来收集那些多余的没人要的普通实参
作用:        收集之后,会把多余实参打包成一个元组
语法:        参数头上1个星星
def func(*args):
	pass
args => arguments
"""
def func(a,b,c,*args):
	print(a,b,c) # 1 2 3
	print(args)  # (4,5,6)

func(1,2,3,4,5,6)

# 任意个数值得累加和
def mysum(*args):
	total = 0
	for i in args:
		total += i
	print(total)
mysum(1,2,3,4,4,45,10,100)

(2) 关键字收集形参

"""
关键字收集形参:专门用来收集那些多余的没人要的关键字实参
作用:        收集之后,会把多余关键字实参打包成一个字典
语法:        参数头上有2个星星
def func(**kwargs):
	pass
kwargs => keyword arguments
"""

def func(a,b,c,**kwargs):
	print(a,b,c)
	print(kwargs) # {'f': 100, 'e': 200, 'z': 12}
func(c=1,a=3,b=10,f=100,e=200,z=12)

# 案例: 拼接任意个数值变成字符串
def func(**kwargs):
	strvar1 = ""
	strvar2 = ""
	# 定义职位信息
	dic = {"monitor":"班长","classflower":"班花"}
	print(kwargs)
	# 共5次循环
	for k,v in kwargs.items():
		if k in dic:
			# 将2次循环的结果通过+= 拼接在一起
			strvar1 += dic[k] + ":" + v + "\n"			
		else:
			# 将3次循环的结果通过+= 拼接在一起
			strvar2 += v + " , "
	print(strvar1.strip())
	print("划水群众:",strvar2.strip(" , "))
		
	"""
	# print(k,v)
	k       v
	monitor 赵万里
	classflower 马春陪
	water1 赵沈阳
	water2 李虎凌
	water3 刘子涛
	{'monitor': '赵万里', 'classflower': '马春陪', 'water1': '赵沈阳', 'water2': '李虎凌', 'water3': '刘子涛'}
	"""

func(monitor="赵万里",classflower="马春陪",water1="赵沈阳",water2="李虎凌",water3="刘子涛")

(3)命名关键字参数

"""
(1) def func(a,b,*,c,d) 跟在*号后面的c和d是命名关键字参数
(2) def func(*args,e,**kwargs) 加在*args和**kwargs之间的参数都是命名关键字参数

命名关键字参数 : 在调用函数时,必须使用关键字实参的形式来进行调用;
"""
# 定义方法一
def func(a,b,*,c,d):
	print(a,b)
	print(c,d)
	
# func(1,2,3,4) # 报错,加了*之后,变成了一种强制性的语法。*后面的参数变成了关键字参数
# 必须指定关键字实参,才能对命名关键字形参进行赋值
func(1,2,c=3,d=4)

# 定义方法二
def func(*args,e,**kwargs):
	print(args)   # (1, 2, 3, 4)
	print(e)      # 3
	print(kwargs) # {'a': 1, 'b': 2}
func(1,2,3,4,a=1,b=2,e=3)

星号的使用

"""
* 和 ** 如果在函数的定义处使用:
	*  把多余的普通实参打包成元组
	** 把多余的关键字实参打包成字典
	
* 和 ** 如果在函数的调用处使用:
	*  把元组或者列表进行解包
	** 把字典进行解包
"""

def func(a,b,*,c,d):
	print(a,b)
	print(c,d)

tup = (1,2)
# 函数的调用处 *号用法
func(*tup,c=3,d=4) # func(1,2,c=3,d=4)

# 函数的调用处 **号用法
dic={"c":3,"d":4}
func(1,2,**dic)    # func(1,2,c=3,d=4)

# 综合写法
# 函数的调用处
tup = (1,2)
dic={"c":3,"d":4}
func(*tup,**dic)

# 定义成如下形式,可以收集所有的实参
def func(*args,**kwargs):
	pass

总结

# 总结: 当所有的形参都放在一起的时候,顺序原则:
"""
普通形参 -> 默认形参 -> 普通收集形参 -> 命名关键字形参 -> 关键字收集形参
"""

# 综合练习
def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
# 以上两个函数 打印结果
#(一)
f1(1, 2) # a =1 b=2 c=0 args=() kw={}
f1(1, 2, c=3) # a=1,b=2,c=3,args=() kw={}
f1(1, 2, 3, 'a', 'b') #a=1 b=2 c=3 args=(a,b) kw={}
f1(1, 2, 3, 'a', 'b', x=99) # a=1 b=2 c=3 args=(a,b) kw={x:99}
f2(1, 2, d=99, ext=None)#a=1 b=2 c=0 d=99 kw={ext:None}

#(二)
args = (1, 2, 3, 4)
kw = {'d': 99, 'x': '#'}
# f1(1,2,3,4,d=99,x=#)
f1(*args, **kw) # a=1 b=2 c=3 args=(4,) kw={d:99,x:#}


#(三)
myargs = (1, 2, 3)
mykw = {'d': 88, 'x': '#'}
# f2(1,2,3,d=88,x=#)
f2(*myargs, **mykw) # a=1,b=2,c=3 d=88 kw={x:#}

#(四)
def f1(a, b, c=0, *args,d,**kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
    print(d)

f1(1,2,3, 'a', 'b',d=67, x=99,y=77) # a=1 b=2 c=3 args=('a','b')  kw={x:99,y:77}
									# d=67

return 自定义函数的返回值

"""
概念:return 把函数内部的数据返回到函数的外面,返回到函数的调用处
1.return + 六大标准数据类型 , 除此之外还可以返回函数 或者 是类对象
2.return 在执行时,意味着终止函数,后面的代码不执行.
3.如果不定义return返回值,默认返回None
"""

(1) return + 六大标准数据类型

def func():
	# return 111
	# return 6.89
	# return "你好帅啊,我爱死你乐"
	# return [1,2,3]
	# return {"a":1,"b":2}
	return 1,2,3 # 返回元组
res = func()
print(res)

(2) return 在执行时,意味着终止函数,后面的代码不执行

def func():
	print(1)
	print(2)
	return 3
	print(4) # 不会执行
res = func()
print(res) # 3

def func():
	for i in range(5):
		if i == 3:
			return 4
		print(i) # 0 1 2
res = func()
print(res) # 4

(3) 如果不定义return返回值,默认返回None

def func():
	pass
	
res = func()
print(res) # None

# 注意点 打印的数据和返回的数据不是等价的,返回的数据是可以自定义的;
res = print(1234)
print(res)  # None

全局变量和局部变量

"""
1.概念
	局部变量:在函数内部定义的变量就是局部变量
	全局变量:在函数外部定义的变量或者在函数内部使用global关键字声明是全局变量

2.作用域:
	局部变量的作用范围仅仅在函数的内部
	全局变量的作用范围横跨整个文件
	
3.生命周期:该变量的作用时长
	内置命名空间 -> 全局命名空间  -> 局部命名空间 (开辟空间顺序)
	内置属性 > 全局属性 > 局部属性 (作用时长:长->短)
"""

1 局部变量

def func():
	# 定义一个局部变量
	a = 1
	# 获取当前的局部变量
	print(a)
	# 修改一个局部变量
	a = 2
	print(a)
	
func()
# print(a) # NameError: name 'a' is not defined

2.全局变量

# 定义一个全局变量
b = 10
# 获取当前的全局变量
print(b)
# 修改一个全局变量
b = 20
print(b)

def func():
	print(b)
func()

3.函数内部定义全局变量

def func():
	global c
	c =30
func()
print(c)

4.函数内部修改全局变量

d = 50
def func():
	global d
	d = 51
func()
print(d) # 当func中有global 语句时打印51

"""
总结:global的使用
如果当前不存在全局变量,可以在函数内部通过global关键字来定义全局变量
如果当前存在全局变量,可以在函数内部通过global关键字来修改全局变量
"""

函数名的使用

python中的函数可以像变量一样,动态创建,销毁,当参数传递,作为值返回,叫第一类对象.其他语言功能有限

  1. 函数名是个特殊的变量,可以当做变量赋值
  2. 函数名可以作为容器类型数据的元素
  3. 函数名可以作为函数的参数
  4. 函数名可作为函数的返回值

(1)动态创建

def func():
	print( "我是func函数")
a = 1
print(a)
a = func # 作为变量赋值
a()

(2)动态销毁

del a
# a() # 报错
func() # func执行没问题

(3)当参数传递

def func2():
	return "我是func2函数"

def func1(f):
	return f() # "我是func2函数"

res = func1(func2)
print(res)

(4)作为值返回

def func3():
	print( "我是func3函数" )
	
def func4(f):
	return f
res = func4(func3)	
print(res)
res()

(5)函数名可以作为容器类型数据的元素

lst = [func,func3]
for i in lst:
	i()

给函数定义文档

__doc__ 或者help查看文档

def big_chang_cishen(something):
	"""
	功能: 教你怎么吃大肠
	参数: 吃的内容
	返回值: 是否满意
	"""
	print("把{}洗一洗".format(something))
	print("直接找肠子头,放嘴里,吸一下")
	print("擦擦嘴,满意的放下肠子头")
	return "吃完了,真好吃~"
	
big_chang_cishen("生肠子")
# 方法一
res = big_chang_cishen.__doc__
print(res) 

# 方法二
help(big_chang_cishen)

函数的嵌套

  • (1) 内部函数可以直接在函数外部调用么 不行
  • (2) 调用外部函数后,内部函数可以在函数外部调用吗 不行
  • (3)内部函数可以在函数内部调用吗 可以
  • (4)内部函数在函数内部调用时,是否有先后顺序 有的
    • python 中需要先定义在调用
    • 在其他语言中有预加载的机制,提前把函数驻留到内存中,然后再去编译脚本内容
    • python没有预加载函数的机制,只能先定义在调用
"""
互相嵌套的两个函数:
	包裹在外层的叫做外函数,内层的就是内函数
"""
def outer():
	# inner() # 需先定义才能调用,否则报错
	def inner():
		print("我是inner函数")

LEGB原则(就近找变量原则)

# LEGB 原则
a=1
def outer():
	a=2
	def inner():
		def smaller():	
			print(a)
		smaller()
	inner()
outer()

"""
LEGB原则(就近找变量原则)
#找寻变量的调用顺序采用LEGB原则(即就近原则)
B —— Builtin(Python);Python内置模块的命名空间      (内建作用域)
G —— Global(module); 函数外部所在的命名空间        (全局作用域)
E —— Enclosing function locals;外部嵌套函数的作用域(嵌套作用域)
L —— Local(function);当前函数内的作用域            (局部作用域)
依据就近原则,从下往上 从里向外 依次寻找
"""

nonlocal的使用 (用来修改局部变量)

"""
nonlocal遵循LEGB原则
(1) 它会找当前空间上一层的变量进行修改
(2) 如果上一层空间没有,继续向上寻找
(3) 如果最后找不到,直接报错
"""

# (1)它会找当前空间上一层的变量进行修改
def outer():
	a = 10
	def inner():
		nonlocal a  # 此时修改的outer内的a
		a = 20
		print(a) # 20
	inner()
	print(a) # 20
outer()

# (2)如果上一层空间没有,继续向上寻找
def outer():
	a = 20
	def inner():
		# a = 15 # 没有这行,则nonlocal修改的是 最外层的a
		def smaller():
			nonlocal a
			a = 30
			print(a)
		smaller()
		print(a)
	inner()
	print(a)
outer()

# (3)如果最后找不到,直接报错
"""nonlocal 只能修改局部变量"""
"""
a = 20
def outer():	
	def inner():
		def smaller():
			nonlocal a
			a = 30
			print(a)
		smaller()
		print(a)
	inner()
	print(a)
outer() # SyntaxError 无法修改全局的a
"""

# (4) 不通过nonlocal 是否可以修改局部变量呢?ok
def outer():
	lst = [1,2,3]
	def inner():
		lst[-1] = 3000
	inner()
	print(lst)
outer()

全局变量 与 局部变量 及 其关键字的使用

"""
#局部变量:函数内部的变量是局部变量,作用域仅在函数内部可见(局部命名空间)
#全局变量:函数外部的变量是全局变量,作用域横跨整个文件(全局命名空间)
#内置函数:内建命名空间

-- globals() :返回字典,存放着全局作用域所有内容
-- locals()  :返回字典,当前作用域所有内容(locals调用之前的变量)
-- global    :关键字:声明全局变量获修改全局变量
-- nonlocal  :关键字:修改局部变量(当前函数上一层的局部变量)
"""

闭包函数

"""
互相嵌套的两个函数,如果内函数使用了外函数的局部变量
并且外函数把内函数返回出来的过程,叫做闭包
里面的内函数叫做闭包函数

是不是闭包?
	1.内函数用了外函数的那个局部变量
	2.外函数返回内函数
"""

1.基本语法形式

def zhaoshenyang_family():
	father = "马云"
	def hobby():
		print("我对钱没有一丝丝的兴趣,我不看重钱,这是我爸爸{}说的".format(father))
	return hobby

func = zhaoshenyang_family()
func()

2.闭包的复杂形式

def zhaowanli_family():
	gege = "王思聪"
	didi = "鞋王,高振宁"
	money = 1000
	
	def gege_hobby():
		nonlocal money
		money -= 500
		print("我交朋友不在乎他有没有钱,反正都没有我有钱.钱物还剩下{}".format(money))
		
	def didi_hobby():
		nonlocal money
		money -= 400
		print("家里有鞋柜,各式各样的奢侈鞋,一双大概20~30万,钱物还剩下{}".format(money))
	
	def big_master():
		return [gege_hobby,didi_hobby]
	
	return big_master

func = zhaowanli_family()
print(func) # <function zhaowanli_family.<locals>.big_master at 0x000000212FD9BAE8>
lst = func()
print(lst)

3.使用 __closure__ , cell_contents 判定闭包

"""如果返回的元组中有数据说明是闭包,谁的生命周期被延长就打印谁"""
tup = func.__closure__
print(tup) # (<cell at 0x00: function object at 0x001>, <cell ..>)

# 先获取第一个单元格  cell_contents获取对象中的内容
func1 = tup[0].cell_contents
"""打印闭包函数didi_hobby中,生命周期被延长的属性"""
# 如果一个变量都没有,则没有形成闭包
print(func1.__closure__[0].cell_contents) # 哪些变量的生命周期被延长了。
func1()
	
# 在获取第二个单元格  cell_contents获取对象中的内容
func2 = tup[1].cell_contents
"""打印闭包函数gege_hobby中,生命周期被延长的属性"""
print(func2.__closure__[0].cell_contents)
func2()

闭包的特点

特点:在闭包函数中,内函数使用了外函数的局部变量,
该变量会与内函数发生绑定,延长该变量的生命周期,
持续到脚本执行结束。

def outer(val):
	def inner(num):
		return val + num
	return inner
	
func = outer(10)
res = func(15)
print(res) # 25

闭包的意义

闭包可以优先使用外函数中的变量, 并对闭包中的值起到了封装保护的作用.外部无法访问。

"""全局变量的作用域大,容易被篡改"""
num = 0
def click_num():
	global num
	num += 1 # num = num + 1
	print(num)
click_num()
click_num()
click_num()
num = 100
click_num() # 被全局变量篡改
click_num()

# 改造,用闭包来实现
def outer():
	x = 0
	def click_num():
		nonlocal x
		x += 1
		print(x)
	return click_num

click_num = outer()
click_num()
x = 100
click_num() # 不会造成影响

匿名函数

# 匿名函数 : lambda表达式
"""
概念: 用一句话来表达只有返回值的函数
语法: lambda 参数 : 返回值
特点: 简洁,高效
"""

(1) 无参的lambda表达式

def func():
	return "hello"

# 改造
func = lambda : "hello"
print(  func()  )

(2) 有参的lambda表达式

def func(n):
	return id(n)

# 改造
func = lambda n : id(n)
print( func(100) )

三元表达式

# 三元运算符
"""语法: 真值 if 条件表达式 else 假值
如果条件表达式成立为True , 返回if前面的真值,反之,返回else后面的假值
"""
n = 13
res = "偶数" if n % 2 == 0 else "奇数"
print(res)

(3) 带有判断条件的lambda表达式

def func(n):
	if n % 2 == 0:
		return "偶数"
	else:
		return "奇数"

# 改造
func = lambda n : "偶数" if n % 2 == 0 else "奇数"
print( func(44) )

练习

# 比较两者之间的最大值进行返回
def func(x,y):
	if x > y:
		return x
	else:
		return y

# 改造
func = lambda x,y : x if x>y else y
print(  func(40,30)  )

localsglobals 使用 (了解)

1. locals 获取当前作用域所有的变量

# 1.全局空间
"""
locals 在函数外 , 获取的是打印之前所有的全局变量
locals 在函数内 , 获取的是locals调用之前所有的局部变量
"""
"""
def func():
	a1 = 1
	b2 = 2

a = 1
b = 2
res = locals()
c = 3
print(res) # 变量c能获取,变量d不能获取
d = 4
"""
# 2.局部空间
"""
a = 1
b = 2
def func():
	a1 = 1
	b2 = 2
	res = locals()
	c3 = 3
	print(res) # 只有a1和b2
	d4 = 4
c = 3
func()
d = 4
"""

2. globals 只获取全局空间的全局变量

"""
globals 在函数外 , 获取的是打印之前所有的全局变量
globals 在函数内 , 获取的是调用之前所有的全局变量
"""
# 1. 全局空间
"""
def func():
	a1 = 1
	b2 = 2

a = 1
b = 2
res = globals()
c = 3
print(res) # a, b, c 和其他全局属性,没有变量d
d = 4
"""

# 2.局部空间
"""
a = 1
b = 2
def func():
	a1 = 1
	b2 = 2
	res = globals()
	c3 = 3
	print(res) # 由a,b,c 变量
	d4 = 4
c = 3 
func() # globals() 相当于在此处调用
d = 4
"""

globals 返回的是内置系统的全局字典

"""
dic = globals()
print(dic)
## 通过字符串可以创建全局变量
dic["wangwen"] = "18岁"
print(wangwen)
"""

# 批量创建全局变量
def func():
	dic = globals()
	for i in range(1,5):
		# 批量在dic当中添加键值对,以创建全局变量
		dic[ "a%d" % (i) ] = i 
		"""
		dic["a1"] = 1
		dic["a2"] = 2
		dic["a3"] = 3
		dic["a4"] = 4
		"""
func()
print(a1,a2,a3,a4) # 可获取到全局变量

递归函数

1. 基本使用

"""
递归函数 : 自己调用自己的函数 , 叫做递归函数
递 : 去
归 : 回
一去一回叫做递归
"""
def digui(n):
    print(n,"<==1==>")
    if n > 0:
        digui(n-1)
    print(n,"<==2==>")

digui(5)

"""
# 去的过程
n = 5 print(5,"<==1==>")  if 5 > 0:   digui(5-1) =>  digui(4) 代码阻塞在第4行
n = 4 print(4,"<==1==>")  if 4 > 0:   digui(4-1) =>  digui(3) 代码阻塞在第4行
n = 3 print(3,"<==1==>")  if 3 > 0:   digui(3-1) =>  digui(2) 代码阻塞在第4行
n = 2 print(2,"<==1==>")  if 2 > 0:   digui(2-1) =>  digui(1) 代码阻塞在第4行
n = 1 print(1,"<==1==>")  if 1 > 0:   digui(1-1) =>  digui(0) 代码阻塞在第4行
n = 0 print(0,"<==1==>")  if 0 > 0: 不成立 print(0,"<==2==>") 到此最后一层函数空间彻底执行完毕

# 回的过程
回到上一层函数空间  n = 1 代码在第4行的位置,继续往下执行  print(1,"<==2==>")
回到上一层函数空间  n = 2 代码在第4行的位置,继续往下执行  print(2,"<==2==>")
回到上一层函数空间  n = 3 代码在第4行的位置,继续往下执行  print(3,"<==2==>")
回到上一层函数空间  n = 4 代码在第4行的位置,继续往下执行  print(4,"<==2==>")
回到上一层函数空间  n = 5 代码在第4行的位置,继续往下执行  print(5,"<==2==>")

到此递归函数执行结束..
打印 543210012345
"""

"""
每次调用函数时,都要单独在内存当中开辟空间,叫做栈帧空间,以运行函数中的代码

递归总结:
	(1)递归实际上是不停的开辟栈帧空间和释放栈帧空间的过程,开辟就是去的过程,释放就是回的过程
	(2)递归什么时候触发归的过程:
		1.当最后一层栈帧空间执行结束的时候,触发归的过程.
		2.当遇到return返回值的时候终止当前函数,触发归的过程.
	(3)递归不能无限的去开辟空间,可能造成内存溢出,蓝屏死机的情况,所以一定要给予跳出的条件(如果递归的层数太大,不推荐使用)
	(4)开辟的一个个栈帧空间,数据是彼此独立不共享的.
"""

# 递归不能不限开辟空间
"""官方说法最大默认是1000层."""

2.使用递归实现任意数n的阶乘

# 普通实现
# 5! =5 *4*3*2*1
n = 5
total = 1
for i in range(n,0,-1):
	total *= i
print(total) # 120

# 递归实现
def jiecheng(n):
	if n <= 1:
		return 1
	return jiecheng(n-1) * n
	
print(jiecheng(2))
# jiecheng(1) => 1 
# jiecheng(2) => jiecheng(1) * 2 => 1 * 2
# jiecheng(3) => jiecheng(2) * 3 => 1 * 2 * 3
# jiecheng(4) => jiecheng(3) * 4 => 1 * 2 * 3 * 4
# jiecheng(5) => jiecheng(4) * 5 => 1 * 2 * 3 * 4 * 5
print(jiecheng(5))
"""
代码解析:
去的过程:
n = 5 return jiecheng(n-1) * n => jiecheng(4) * 5
n = 4 return jiecheng(n-1) * n => jiecheng(3) * 4
n = 3 return jiecheng(n-1) * n => jiecheng(2) * 3
n = 2 return jiecheng(n-1) * n => jiecheng(1) * 2
n = 1 return 1

回的过程:
n = 2 return jiecheng(1) * 2 => 1 * 2
n = 3 return jiecheng(2) * 3 => 1 * 2 * 3
n = 4 return jiecheng(3) * 4 => 1 * 2 * 3 * 4
n = 5 return jiecheng(4) * 5 => 1 * 2 * 3 * 4 * 5

到此程序结束:
返回  1 * 2 * 3 * 4 * 5
"""

3. 使用尾递归来实现任意数的阶乘

""" return 在哪调用,在哪返回 """
"""自己调用自己,且返回时非运算表达式,只是函数本身"""
"""
特点:
	尾递归只开辟一个空间,不会无限的开辟,在一个空间里面去计算最后的结果进行返回,比较节省空间,有的解释器支持尾递归的调用特点
	但是cpython解释器目前不支持
写法:
	所有运算的值都在函数的参数中计算完毕,最后返回运算的参数;
"""

def jiecheng(n,endval):
	if n <= 1:
		return endval
	return jiecheng(n-1 , n * endval)
res = jiecheng(5,1) # 5*4*3*2*1
print(res)

"""
代码解析:
去的过程
n = 5 ,endval = 1 return jiecheng(n-1 , n * endval) => jiecheng(4,5*1) => 5*1*4*3*2
n = 4 ,endval = 5*1 return jiecheng(n-1 , n * endval) => jiecheng(3,5*1*4) => 5*1*4*3*2 
n = 3 ,endval = 5*1*4 return jiecheng(n-1 , n * endval) => jiecheng(2,5*1*4*3) => 5*1*4*3*2 
n = 2 ,endval = 5*1*4*3 return jiecheng(n-1 , n * endval) => jiecheng(1,5*1*4*3*2) => 5*1*4*3*2 
n = 1 ,endval = 5*1*4*3*2   if n <= 1 成立  return endval
endval = 5*1*4*3*2 
最下层空间的返回值 是 5*4*3*2*1  最上层接收到的返回值也是 5*4*3*2*1
最下层和最上层返回的结果是一致的,所以对于尾递归来说,只需要考虑去的过程,无需考虑回的过程即可完成;
"""

# 优化代码1
def jiecheng(n,endval=1):
	if n <= 1:
		return endval
	return jiecheng(n-1 , n * endval)
res = jiecheng(5) # 5*4*3*2*1 # 可以不传,但是会被篡改
print(res,"<00000>")

# 优化代码2 [把尾函数调用把需要的参数值隐藏起来,避免篡改.]
def outer(n):
	def jiecheng(n,endval=1):
		if n <= 1:
			return endval
		return jiecheng(n-1 , n * endval)
	return jiecheng(n,1) # 120,不是闭包
print(outer(5))

# 优化代码3(扩展)
# 闭包实现
def outer(n):
	endval = 1
	def jiecheng(n):
		nonlocal endval
		if n <= 1:
			return endval
		endval *= n 
		return jiecheng(n-1)
	return jiecheng
func = outer(5)
print(func(5),"<===111==>")


# ### 3.使用递归来完成斐波那契数列
""" 1 1 2 3 5 8 13 21 34 ... """

def feib(n):
	if n == 1 or n == 2:
		return 1
		
	# 上一个结果 + 上上个结果
	return feib(n-1) + feib(n-2)
print(feib(5))
"""
# 代码解析:
n = 5               feib(5) => 3 + 2 => return 5  
		feib(4)        +         feib(3)
    feib(3)+feib(2)          feib(2)+feib(1) => 1 + 1 => 2
feib(2)+feib(1)+feib(2) => 1 + 1 + 1 => 3    
"""

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值