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))

#可以看到这些不同数据类型的所有对象都被装进了同一个元组~


接下来对函数的返回值做个小结:

  1. 在python中,如果没有给函数定义任何返回值,默认返回值为None。

  2. python中的函数不可以同时retrun多次,当函数执行的时候,读到第一个retrun时,函数就会退出执行,retrun后面的代码都将不会被执行。

  3. 在python的函数中,只return一个对象的话,return的对象是什么类型的数据,返回的就是什么类型的数据。

  4. 在python函数中,如果要return多个对象,这些对象同时都会被装进一个元组并返回。

关于python函数的返回值在这里就说完了,接下来说说函数传参。




三.关于函数的参数。

说的函数的参数,就要先说说形参和实参的概念了,我理解的型参,就是函数用来接受实际参数的一个“位置”,这个位置只有在函数在调用的时候,才会被分配到内存中去,一旦函数调用结束,型参所在的内存单元会被释放,换句话说,这种形参只能在函数内部使用。

def func1(a,b):

    c=a+b

    return c

#上面定义了一个函数,函数名为func1,里面的a和b就是型参。


下面在说说实参,实参可以是表达式,常量,变量,函数,以及各种对象....总之要有实际的值,因为必须要有确定的值,才可以把它传递给型参。(实参,就是调用函数时,给函数传的值或参数。)

print func1(1,2) #调用上面定义的func1函数

>>>3

在调用func1函数时,传给函数内部型参的1,2就是所谓的实参。

下面来说说函数的传参方式。


  1. 按形参的顺序给函数传递参数。

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


三.函数参数收集。

  1. 一次性传递多个参数,将多个参数传递到一个元组中。

如果想要让一个形参可以收集多个值,但值这些值会被装进元组,当作一个参数传递给函数,想实现这种效果,只要在定义函数时,给指定的形参前面加一个*星号就可以做到。

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(),这三个函数在本篇文章中,只做个简单的解释,等博主写到面向对象编程时,会详细说下这三个函数的具体功能。

  1. 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中函数不只可以向后引用,也可以向前引用。

下面是两个例子:

  1. 最常见的向后引用。

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函数,以及作用域,递归等知识点的主要内容,如果未能解决你的问题,请参考以下文章

一步一步教你认识闭包

python基础知识

九python沉淀之路--递归全局变量局部变量作用域

python基础-基础知识考试_day5 (包括:函数_递归等知识)

js关于“变量提升作用域私有作用域等知识点”高级解题思路

python基础 函数局部变量 全局变量 递归