3.关于python函数,以及作用域,递归等知识点
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3.关于python函数,以及作用域,递归等知识点相关的知识,希望对你有一定的参考价值。
一.使用函数编程的好处。
大大的提高了代码的重用行,重复的逻辑或者操作,可以定义到一个函数里,多次调用。
下面是关于提高代码重用性的例子。
现在老板让你写一个监控程序,监控服务器的系统状况,当cpu\memory\disk等指标的使用量超过阀值时即发邮件报警,你掏空了所有的知识量,写出了以下代码。
while True:
if cpu利用率 > 90%:
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接
if 硬盘使用空间 > 90%:
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接
if 内存占用 > 80%:
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接
上面这段代码可以看出,每一段代码的重复的地方特别多。
如果日后还需要增加群发功能,从上到下,所有的代码都需要去修改。
def 发送邮件(内容)
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接
while True:
if cpu利用率 > 90%:
发送邮件(‘CPU报警‘)
if 硬盘使用空间 > 90%:
发送邮件(‘硬盘报警‘)
if 内存占用 > 80%:
发送邮件(‘内存报警‘)
这段代码就是使用了函数式编程写出的代码,从这段代码中可以有个很明显的特点,把重复的代码单独拿出来,定义了一个函数(也就是放到一个公共的空间,也相当于给这段代码起了个名字),如果以后需要多次使用这个代码,只要调用这个名字就可以了。
二.关于python中函数的返回值。
当定义了一个函数,如果不使用return给任何返回值,默认就会返回None。
下面就是例子。
def func01():
print "this is func"
def func02():
print "this is func"
return 2
test1 = func01()
>>>this is func
test2 = func02()
>>>this is func
print test1
>>>None
print test2
>>>2
在上面定义了两个函数,分别是func01和func02,这两个函数的功能都是打印输出同一句话“this is func”,func01没有定义任何返回值,返回给test1变量的是个空值(None),func02使用return定义了一个返回值,返回的是数字2,返回给test2的就是数字2。
那么一个函数,在被调用一次的时候,是否可以同时!注意!是同时!返回多个值呢?(不同if分支判断中的return不能算同时!)
我们来试一下。
def func01():
print "this is func"
#定义的第一个函数func01,没有定义任何返回值。
def func02():
print "this is func"
return 2
#定义的第二个函数func02,定义了一个返回值,返回一个整数2。
def func03():
print "this is func"
return 1
return 2
#定义的第三个函数func03,使用两次return,定义了两个返回值,分别是1和2。
def func04():
print "this is func"
return 1,2,3,4
#第四个函数func4,使用一个return返回四个整数,这四个整数使用逗号隔开。
test1 = func01()
test2 = func02()
test3 = func03()
test4 = func04()
#将这四个函数的返回值分别赋给变量,然后看看每个函数的返回值都是什么。
print test1
>>>None
#第一个函数的返回值为空,因为之前说了,函数如果不定义任何返回值,默认就返回None空值。
print test2
>>>2
#第二个函数,返回了一个整数2,因为使用return指定了返回值,所以就返回了一个整数2,如果返回值是字典,那么return返回的也是个字典。(当返回值只有一个的时候,retrun什么数据类型,就会返回什么数据类型!!这点很重要!)
print test3
>>>1
#第三个函数,在定义的时候写了两个return,但是只返回了一个值,这个值是整数1。
#明明使用两个return,但是只返回了一个返回值?!~是的,没错,下面要强调一个关于python函数很重要的知识点!
#当python函数在之行的时候,一旦遇到return,函数直接退出!return后面的所有代码都不会被执行!!!!!这点很重要!!!
不信我们可以试试~
现在我将func03函数做了一下修改。
def func03():
print "this is func"
return 1
print "hamasaki ayumi"
return 2
#我在两个retrun中间插了一行代码,打印字符串“hamasaki ayumi”,这个字符串放到了第一个return后面,看看会不会被执行
test3 = func03()
print test3
>>>1
#见证“奇迹”的时刻到了。
#func03函数依旧只返回了第一个rerun中定义的整数1,第一retrun执行结束后,函数直接退出了,retrun 1后面的所有代码都没有被执行!这也就验证了刚才所说的,当函数执行时,遇到retrun,返回相应的返回值之后,函数直接退出,retrun后面的所有代码都不会被执行。
print test4
>>>(1, 2, 3, 4)
#第四个函数,也只返回了一个元组,之前定义的返回值,1,2,3,4四个整数,被装进了同一个元组中,这也说明了一个问题,就是,当retrun要返回多个值的时候,会把这些同时返回的多个值,装进同一个元组中。
那么可能有人会问,如果同时返回多种数据类型呢?在同一个返回值中,有字典,有列表,有元组会是什么效果?
可以肯定的告诉你,返回的这些字典,列表,元组,字符串,统统会被打包进一个元组~
做个测试吧。
现在将func04函数做了一下修改。
修改了一下func04的返回值,现在这个返回值里面充满了各种数据类型,有字典,有数字,有字符串,有元组,有列表,看看最后会返回值是什么。
def func04():
print "this is func"
return 1,2,3,4,[‘a‘,‘b‘,‘c‘,‘d‘],‘hello‘,{‘k1‘:‘v1‘,‘k2‘:‘v2‘},(9,8,7,6,5)
test4 = func04()
print test4
>>>(1, 2, 3, 4, [‘a‘, ‘b‘, ‘c‘, ‘d‘], ‘hello‘, {‘k2‘: ‘v2‘, ‘k1‘: ‘v1‘}, (9, 8, 7, 6, 5))
#可以看到这些不同数据类型的所有对象都被装进了同一个元组~
接下来对函数的返回值做个小结:
在python中,如果没有给函数定义任何返回值,默认返回值为None。
python中的函数不可以同时retrun多次,当函数执行的时候,读到第一个retrun时,函数就会退出执行,retrun后面的代码都将不会被执行。
在python的函数中,只return一个对象的话,return的对象是什么类型的数据,返回的就是什么类型的数据。
在python函数中,如果要return多个对象,这些对象同时都会被装进一个元组并返回。
关于python函数的返回值在这里就说完了,接下来说说函数传参。
三.关于函数的参数。
说的函数的参数,就要先说说形参和实参的概念了,我理解的型参,就是函数用来接受实际参数的一个“位置”,这个位置只有在函数在调用的时候,才会被分配到内存中去,一旦函数调用结束,型参所在的内存单元会被释放,换句话说,这种形参只能在函数内部使用。
def func1(a,b):
c=a+b
return c
#上面定义了一个函数,函数名为func1,里面的a和b就是型参。
下面在说说实参,实参可以是表达式,常量,变量,函数,以及各种对象....总之要有实际的值,因为必须要有确定的值,才可以把它传递给型参。(实参,就是调用函数时,给函数传的值或参数。)
print func1(1,2) #调用上面定义的func1函数
>>>3
在调用func1函数时,传给函数内部型参的1,2就是所谓的实参。
下面来说说函数的传参方式。
按形参的顺序给函数传递参数。
def func1(name,city):
print "name:%s city:%s" %(name,city)
#定义了一个函数,里面定义了两个形参,分别是name和city。
func1 ("hamasaki ayumi","Fukuoka")
#刚刚定义的func1函数定义了两个形参,先定义的name,再定义的city,现在按照刚刚定义的顺序给函数传参。
>>>name:hamasaki ayumi city:Fukuoka
参数被按顺序传递到了函数中。
如果传参时不按顺序呢?
func1 ("Fukuoka","hamasaki ayumi")
>>>name:Fukuoka city:hamasaki ayumi
#所传的参数顺序反过来了。
2.手动指定形参和实参的对应关系,一个函数中定义了很多型参,这些形参的顺序很难记住,如果不想按照型参的顺序去传递参数,在调用函数的时候,可以手动指定哪个形参去接收哪个实参。(这个也叫叫关键字参数!)
def func1(name,city):
print "name:%s city:%s" %(name,city)
func1 (city = "Fukuoka",name = "hamasaki ayumi")
>>>name:hamasaki ayumi city:Fukuoka
从这可以看出,手动指定了形参和实参的对应关系,即使不按照顺序去传参数,参数传递的位置也不会出错。(前提是形参和实参的顺序一定要对应)
3.默认参数,默认参数是函数在定义过程中,在形参中指定的,当调用函数的时候,没有给该函数的形参传递指定的实参,那么这个形参直接等于在创建函数时定义的默认参数。
(说简单一点,就是在定义函数的时候,给了某个参数一个默认参数,如果没传参数,这个参数直接等于它的默认值)
下面是关于默认参数的例子:
def func2(name,sex="male"): #创建函数,定义了一个默认值sex默认等于male
print "name:%s sex:%s" %(name,sex)
func2("name = ayumi") #在调用函数的时候,只传了一个参数,在调用函数的时候没有给sex传参,sex默认就等于了male。
>>>name:ayumi sex:male
func2(name = "ayumi",sex = "female")
再次调用下func2函数,给sex也传一个参数,看看是否可以覆盖默认值。
>>>name:ayumi sex:female
三.函数参数收集。
一次性传递多个参数,将多个参数传递到一个元组中。
如果想要让一个形参可以收集多个值,但值这些值会被装进元组,当作一个参数传递给函数,想实现这种效果,只要在定义函数时,给指定的形参前面加一个*星号就可以做到。
def func1(a,*args): #定义了两个形参,分别时a和args,其中在args前面加了一个*,来看看传参的效果是怎么样的。
print a
print args
func1(1,2,3,4,5,6)
>>>1
(2, 3, 4, 5, 6)
参数1给了a,2,3,4,5,6打包成了元组,传给了args。
在参数前面加上*就是可变参数。在函数内部,参数args接收得到的是一个tuple元组,调用该函数时,可以传入任意个参数,包括0个参数(如果不给可变的形参传递任何参数,它默认就会等于一个空元组)。
我们可以来测试下。
def func1(a,*args):
print a
print args
func1(1)#调用func1函数的时候,没有给args传递任何实参数,看看会返回什么。
>> 1
()
args返回了一个空的元组。
当*args遇到关键字参数的时候会出现什么样的效果呢?
func1(1,k1=‘aaa‘)
Traceback (most recent call last):
File "/Users/macbook/PycharmProjects/untitled1/2day.py", line 5, in <module>
func1(1,k1=‘aaa‘)
TypeError: func1() got an unexpected keyword argument ‘k1‘
#结果抛出了个异常~
如果想传递多个关键字参数给函数,在定义形参的时候,需要在前面加**两个星号,下面就来说说这种可以传递多个关键字参数的写法。
2.一次性传递多组参数,每组参数被传递到一个字典中,作为字典的键值对。
让一个形参可以收集多个关键字参数,每个关键字参数都将作为键值对被装进同一个字典,当作一个参数传递给函数,想实现这种效果,只要在定义函数时,给指定的形参前面加两个**星号,就可以实现这种功能。
def func1(a,**kwargs):
print a
print kwargs
func1(1,k1=‘aaa‘,k2=‘ccc‘,k3=‘ddd‘)
>>>1
{‘k3‘: ‘ddd‘, ‘k2‘: ‘ccc‘, ‘k1‘: ‘aaa‘}
func1(1)
>>>1
{}
和一个*星号一样,**星号依旧是可变的形参,两个星号的形参如果不传递任何参数,默认会返回一个空字典。
3.当*单个星号和**两个星号,还有普通的形参放在一起用,会出现什么效果?
def test_func(a,b,c,*args,**kwargs):
print "a = %s" %(a)
print "b = %s" %(b)
print "c = %s" %(c)
print "args= ",args
print "kwargs =",kwargs
test_func(1,2,3,4,5,6,k1="v1",k2="v2")
输出结果如下:
a = 1
b = 2
c = 3
args= (4, 5, 6)
kwargs = {‘k2‘: ‘v2‘, ‘k1‘: ‘v1‘}
四,分解序列传参。
在给python函数传递参数时,如果需要把一个列表,或者元组中的每一个元素拆开,依旧可以适用*单个星号来实现。
不过需要注意的是!!!这次的星号不是放在定义函数的形参前面的!!而是放在实参前面的。
举个例子就可以看明白了。
def func1(*args): #定义了一个函数,给了这个函数一个可变的形参。
print args
接下来调用func1函数,给这个函数的可变的形参传一个列表。
func1([1,2,3,4,5,6])
>>>([1, 2, 3, 4, 5, 6],)
最后,返回了一个元组,整个列表变成了元组中的一个元素。
接下来,我们在给函数传参的时候,在序列前面加一个*星号,看看会出现什么效果。
func1(*[1,2,3,4,5,6])
>>>(1, 2, 3, 4, 5, 6)
#从显示的结果可以看到,列表中的每一个元素,都单独作为一个元素,放在了元组里面。
而不是将一个列表当成一个元素放进元组里。
补充!*星号基本的序列都可以拆开,比如说字符串~
func1(*"hello")
>>>(‘h‘, ‘e‘, ‘l‘, ‘l‘, ‘o‘)
func1("hello")
>>>(‘hello‘,)
这是加星号和不加星号的对比。
字符串中每一个字母都被拆开,放进了元组。
五.如何把字典直接传进函数。
现在有一个字典类型的值,需要把这个字典完整的传到函数中,该怎么做?
首先,我们先来试试,在调用函数的时候,只使用一个*信号,看看能不能把字典传到列表中。
def func1(*args):
print args
首先,试试第一种方法,在函数中定义了一个可变的形参,接受所有参数,将所有接收到的参数,都放到同一个元组中。
func1({‘k1‘:‘v1‘,‘k2‘:‘v2‘})
>>>({‘k2‘: ‘v2‘, ‘k1‘: ‘v1‘},)
在调用func1函数的时候,传参,不做任何分解,直接把字典传给那个可变的形参*args,最后的结果就是,这个字典的确是被传到了函数内部,但是这个字典被放到了一个元组中。
然后我们在试试第二个方法。
还是上面定义的func1函数,在把字典传进去之前,在前面加个*号,看看会是什么效果。
func1(*{‘k1‘:‘v1‘,‘k2‘:‘v2‘})
>>>(‘k2‘, ‘k1‘)
只把两个key放到了元组中,没有达到想要的结果。
第三种方法,在传参的时候使用两个**星号。
def func2(**kwargs):
print kwargs
func2(**{‘k3‘: ‘v3‘, ‘k2‘: ‘v2‘, ‘k1‘: ‘v1‘})
>>> {‘k3‘: ‘v3‘, ‘k2‘: ‘v2‘, ‘k1‘: ‘v1‘}
使用两个**星号,成功的把字典原原本本的传到了函数中。
补充!如果只是按照函数赋值的角度来说的话,
func2(**{‘k3‘: ‘v3‘, ‘k2‘: ‘v2‘, ‘k1‘: ‘v1‘}) 和func2(k1 = ‘v1‘,k2 = ‘v2‘,k3 = ‘v3‘),效果是一模一样的。
五.关于函数与作用域。
说到作用域,就要先来说说变量,什么是变量,变量就是一个值的名字,现在定义一个变量为x = 1,也就是将1这个整数赋值给了x,然后通过引用x这个变量名,可以获得这个整数1,这种形式和字典特别像,通过一个key,去取对应的value,这个变量名和变量值的对应所用的是个看不见的字典,如果想看这个‘字典’,可以使用var()函数来进行查看。
注意啦!!!与作用域息息相关的三个函数var()函数和locals()函数还有global() 这三个函数会放在面向对象的时候一起做补充~~在这里只是简单说一下,先挖个坑~嘿嘿。
这种我们看不到的“字典”就是作用域,除了全局的作用域外,每个函数调用都会创建一个新的作用域。
下面,来看一个现象。
#!/usr/bin/python2.7
# -*- coding:utf-8 -*-
def foo(): #首先,定义了一个函数,这个函数里面定义了一个x=130,然后在函数的外面定义了一个变量,x = 1,执行foo()函数,那么最后x等于多少?
x = 130
x = 1
foo()
print x
>>>1
最后,x还是等于1。
原本以为执行了foo函数后,会重新定义x变量,但是函数执行结束后,x的值并没有发生改变,这就是因为在调用函数foo的时候,新的命名空间被创建了,x = 130只在这个变量的内部作用域(局部的命名空间)起作用,不会影响到函数外部(全局)作用域中的x变量,因此,函数内部的变量都被称为局部变量。
但是如果要在函数的内部访问全局变量该怎么做?
如果在函数内部,只是单纯的读取全局变量,是完全没有问题的,只要不重新赋值就没有任何问题。
(补充~使用global声明或者全局变量是列表,字典之类的可辨类型除外)
不信可以来测试一下。
def f1():
print x
x = 1
f1()
>>> 1
从上面的测试可以看出,如果在函数内部只是访问全局变量的话,是没有任何问题的。
如果函数中有global关键字,那么被global声明的变量,直接变成全局变量。
注意啦!!!!!读取全局变量一般来说,不会出什么问题,但是啊,如果局部变量名或者参数名,和想要访问的全局变量中的变量名有冲突,那么,在这个函数中,就无法直接访问这个全局变量了,局部变量会把全局变量给临时性的“覆盖”。说的通俗点,就是当局部变量和全局变量名相同,在函数内部访问的话,以局部变量为准!!
说到了变量和作用域,又不得不提到三个函数,分别是vars(),globals(),locals(),这三个函数在本篇文章中,只做个简单的解释,等博主写到面向对象编程时,会详细说下这三个函数的具体功能。
locals() 首先上官方解释:Update and return a dictionary containing the current scope‘s local variables. 博主英语比较渣,查了下不会的单词,大概可以翻译为,更新或者返回一个字典,这个字典中包含了当前范围的本地变量。
locals这个函数,根据博主亲测,当放到哪个作用域,就会以字典的形式返回当前作用域中的所有名称空间的所有值(所有的变量名和变量值)。
x = 1
def f1():
a = "abc"
print "locals = ",locals()
f1()
locals = {‘a‘: ‘abc‘}
print locals()
{‘f1‘: <function f1 at 0x102efa668>, ‘__builtins__‘: <module ‘__builtin__‘ (built-in)>, ‘__file__‘: ‘/Users/macbook/PycharmProjects/untitled1/test.py‘, ‘__package__‘: None, ‘x‘: 1, ‘__name__‘: ‘__main__‘, ‘__doc__‘: None}
#分别在全局作用域和f1函数中都调用了一次locals()函数,结果已经很明显了,在f1函数内部调用locals函数后,返回了f1函数作用域中所有的变量名以及对应的变量值,接着,又在函数外,也就是全局作用域调用了一下locals()函数,结果返回了全局作用域中的所有变量名和变量值(名称空间)的使用情况。
2.globals() Return the dictionary containing the current scope‘s global variables. 返回一个字典,包涵当前范围全局变量。
globals函数,用于返回全局变量中所有的变量名以及变量值( 名称空间)的使用情况。
globals函数不管放在任何作用域,显示的都是全局作用域中的变量名和变量值。
3.vars() 这个函数原本想放在面向对象的时候在详细说说的,因为涉及到了“对象”相关的知识点。
先来看看官方怎么解释吧。
def vars(p_object=None): # real signature unknown; restored from __doc__
"""
vars([object]) -> dictionary
Without arguments, equivalent to locals().
#没有参数时,相当于locals()函数。
#这句话就是说,当vars()函数在没传任何参数之前,和locals()函数是一模一样的。
With an argument, equivalent to object.__dict__.
#有一个参数传进来的时候,作用就相当于一个对象的__dict__方法。
"""
return {}
官方的意思就是说vars()这个函数如果不加参数,功能和local函数一样,如果加了参数,就可以以字典的方式,返回这个对象内部的变量,在python这门语言中,一切皆对象,变量名,函数名,都是对象,如果想看这些对象内部都包涵什么变量的话,vars(对象名)就可以看到了,给vars函数传一个对象的名称。
def f1():
a = 1 #在这个例子中,我特别在函数中定义了一个变量a = 1,是为了防止f1对象中变量和f1函数的变量混淆
pass
vars(f1)
>>>{‘x‘: 1}
vars(对象名) = 对象.__dict__ 这两个作用是一模一样的。
下面补充一个关于globals()函数使用的小技巧!
当函数内部变量和全局环境下的变量名一模一样,这时两个一模一样的变量名,就会以函数内部的变量值为准,这样,函数就无法访问这个函数外部同名的全局变量了,如果想访问函数外部的全局变量,就可以借助globals() 函数去拿全局变量。
下面是例子:
在没有使用globals()函数之前,是无法访问同名全局变量的。
name = "suhaozhi"
def test1():
name = "hamasaki"
print name
test1()
>>>hamasaki
函数test1想要访问外部的name = “suhaozhi”这个变量,但是只能访问到函数内部的name = “hamasaki”。
接下来,我们就使用globals()函数去取全局name变量。
name = "suhaozhi"
def test1():
name = "hamasaki"
print globals()[‘name‘]
test1()
>>>suhaozhi
全局变量中name的值被成功取到了。
六.在python中函数不只可以向后引用,也可以向前引用。
下面是两个例子:
最常见的向后引用。
def func1():
print ‘in the func1‘
def func2():
print "in the func2"
func1()
func2()
>>> in the func2
in the func1
2.向前引用。
def func2():
print "in the func2"
func1()
def func1():
print ‘in the func1‘
func2()
>>> in the func2
in the func1
七.函数嵌套。
首先,来看一个函数嵌套的例子,然后分析它的执行过程。
name = "suhaozhi"
def f1():
name = "f1"
def f2():
name = "f2"
print name
f2()
print name
f1()
print name
开始执行f1函数。
第一步:在f1内部加载局部变量name = “f1”.
第二步:加载f2函数。
第三步:执行f2函数,并先打印一个字符串“f2”。
第四步:f1内部的f2函数执行完毕,退出到f1函数,打印f1中的name变量,打印“f1”字符串。
第五步:f1函数执行完毕,退出函数,开始打印全局变量name = "suhaozhi"。
八. 函数递归。
函数自己调用自己,就是所谓的递归。
def func1():
print "in the func1"
func1()
func1()
#上面这个例子,就是基于函数递归的特性完成的一个“死循环”。
func1函数做了两个动作,输出一个"in the func1"然后再次执行func1函数,然后再输出"in the func1"...
会一直循环下去。
所以说,在做函数递归的时候,必须有个明确的结束条件(使用return去终止)。
说简单点,就是在函数中使用if条件判断,然后在指定的条件下return。
下面是一个使用函数递归实现的数字递减。
def func1(n):
print n
if n - 1 == 0:
return n
return func1(n - 1)
func1(10)
#调用func1函数,给n传了一个整数10.
#现在n = 10 打印一次变量n会显示一次10
#开始if判断,10 - 1不等于0,条件不成立,则执行下面的return func1(n - 1),也就是在函数内部继续调用func1函数,并且把n - 1
#这时,n = 9 再次进入if判断 9 - 1也不等于0,条件不成立,然后继续调用func1函数 n继续 - 1 ,此时n = 8 .........以此类推.
#一直到n == 0 执行retrun n
第二点,每次更深入一层递归,问题规模要比上次递归有所减少。
关于这个问题,前两天看到了一个很不错的例子。
# -*- coding:utf-8 -*-
import time
perscon_list = [‘a‘,‘b‘,‘c‘,‘d‘,‘ayumi‘]
def find_person(person_list):
print ‘*‘ * 60
person = person_list.pop(0)
if person_list == False:
print "We don‘t even know her~"
return None
if person == "ayumi":
return "Everyone is a bitch jolin,right?she is a bitch jolin"
#print "%s:Everyone is a bitch jolin,right?she is a bitch join" %(person)
print "请问%s,你认识bitch jolin吗?" %(person)
print "i don‘t know her~ But I can help you ask ",person_list
time.sleep(3)
re = find_person(person_list)
print "%s问的结果是,%s" %(person,re)
return re
print find_person(perscon_list)
上面这个例子的输出结果是:
************************************************************
请问a,你认识bitch jolin吗?
i don‘t know her~ But I can help you ask [‘b‘, ‘c‘, ‘d‘, ‘ayumi‘]
************************************************************
请问b,你认识bitch jolin吗?
i don‘t know her~ But I can help you ask [‘c‘, ‘d‘, ‘ayumi‘]
************************************************************
请问c,你认识bitch jolin吗?
i don‘t know her~ But I can help you ask [‘d‘, ‘ayumi‘]
************************************************************
请问d,你认识bitch jolin吗?
i don‘t know her~ But I can help you ask [‘ayumi‘]
************************************************************
d问的结果是,Everyone is a bitch jolin,right?she is a bitch jolin
c问的结果是,Everyone is a bitch jolin,right?she is a bitch jolin
b问的结果是,Everyone is a bitch jolin,right?she is a bitch jolin
a问的结果是,Everyone is a bitch jolin,right?she is a bitch jolin
Everyone is a bitch jolin,right?she is a bitch jolin
(第二个例子是真正意义上的递归,实现了返回值回传)
递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
堆栈扫盲http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html
尾递归优化:http://egon09.blog.51cto.com/9161406/1842475
关于函数递归的最后补充:
函数自己调用自己,就是所谓的递归,当函数调用自身时,当前函数,和在函数内部调用的“自己”实机上已经是两个不同的函数了,(也就是同一个函数使用了两个不同的命名空间)。
本文出自 “reBiRTH” 博客,请务必保留此出处http://suhaozhi.blog.51cto.com/7272298/1907615
以上是关于3.关于python函数,以及作用域,递归等知识点的主要内容,如果未能解决你的问题,请参考以下文章