day16-递归调用与模块

2020-07-23  本文已影响0人  天行_b6d0

函数的递归调用

一:引入

函数的递归调用:就是在调用一个函数的过程中又直接或间接地调用自己

示例1:直接调用自己
def foo():
    print('hello')
    foo()

foo()
示例2:间接调用自己
def bar():
    print('from bar')
    foo()

def foo():
    print('hello')
    bar()

foo()

为何"死递归"会抛出异常???
因为无限的递归会导致内存溢出,所以python设定了最大的递归层数,这个最大递归层数可以自己设置,但是一般情况下python自身设定的层就已经足够使用了。

import sys
print(sys.getrecursionlimit())
print(sys.setrecursionlimit(2000))

所以:不应该无限递归调用下去,应该在满足某种条件下结束递归调用,然后返回

二:递归调用应该分为两个阶段

1、回溯(挖井) :一层一层地递归调用下去
2、递推(从井里往外跳):在满足某一条件的情况下结束回溯,然后开始向上一层层返回

例1:
salary(5) = salary(4) + 10
salary(4) = salary(3) + 10
salary(3) = salary(2) + 10
salary(2) = salary(1) + 10
salary(1) = 18


n=1   salary(n) = 18
n!=1  salary(n) = salary(n-1) + 10

def salary(n):
    if n == 1:
        return 18
    return salary(n-1) + 10

res=salary(5)
print(res)
例2:将列表中的数字打印出来
nums=[111,[222,[333,[444,[5555,[6666,[777,[888,[9999]]]]]]]]]


def func(l):
    for x in l:
        if type(x) is list:
            # 把自身的代码重新再调用一次
            func(x)
        else:
            print(x)
func(nums)
例3:从小到大排列的一个数字列表,查找某个数是否在里面
nums = [11, 13, 32, 47, 53, 73, 84, 91,101,111,222,333,444,5555]


def binary_search(l,find_num):
    print(l)
    if len(l) == 0:
        print('find_num not exists')
        return
    mid_index = len(l) // 2
    if find_num > l[mid_index]:
        right_l=l[mid_index+1:]
        binary_search(right_l,find_num)
    elif find_num < l[mid_index]:
        left_l=l[:mid_index]
        binary_search(left_l,find_num)
    else:
        print('find it')


binary_search(nums,85)

三元表达式

如下为判断两个数大小的一段:

def max2(x,y):
    if x > y:
        return x
    else:
        return y

可以使用三元表达式简化:

x=111
y=222
res=x if x > y else y
print(res)

三元表达式: 表达式1 if 条件 else 表达式2

列表生成式

1、示例

egg_list=[]
for i in range(10):
    egg_list.append('鸡蛋%s' %i)

egg_list=['鸡蛋%s' %i for i in range(10)]

2、语法

[expression for item1 in iterable1 if condition1
for item2 in iterable2 if condition2
...
for itemN in iterableN if conditionN
]
类似于
res=[]
for item1 in iterable1:
    if condition1:
        for item2 in iterable2:
            if condition2
                ...
                for itemN in iterableN:
                    if conditionN:
                        res.append(expression)

3、优点:方便,改变了编程习惯,可称之为声明式编程

匿名函数

一、什么是匿名函数
匿名就是没有名字
def func(x,y,z=1):
    return x+y+z

匿名
lambda x,y,z=1:x+y+z #与函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放,除非让其有名字
func=lambda x,y,z=1:x+y+z 
func(1,2,3)
#让其有名字就没有意义
二、有名函数和匿名函数对比

有名函数:循环使用,保存了名字,通过名字就可以重复引用函数功能

匿名函数:一次性使用,随时随时定义

匿名函数的应用:max,min,sorted,map,reduce,filter

模块

1、什么是模块

模块就是一组功能的集合体,我们的程序可以导入模块来复用模块里的功能。

模块可以分为四个通用类别:

--  1 使用python编写的.py文件

--  2 已被编译为共享库或DLL的C或C++扩展

--  3 把一系列模块组织到一起的文件夹(注:文件夹下有一个init.py文件,该文件夹称之为包)

--  4 使用C编写并链接到python解释器的内置模块

2、为什么要使用模块

1、从文件级别组织程序,更方便管理
随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用

2、拿来主义,提升开发效率
同样的原理,我们也可以下载别人写好的模块然后导入到自己的项目中使用,这种拿来主义,可以极大地提升我们的开发效率

ps:
如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py被称为脚本script。

3、如何使用模块(以spam为例)

(1)import

import spam
首次导入模块发生的事情
1、触发被导入的模块的运行,产生一个模块的名称空间,把模块中的名字都丢进去。

2、会在当前执行文件中得到一个名字spam,该名字是指向被导入模块的名称空间的。

3、之后的导入,名字spam直接引用首次导入产生的名称空间,不会再执行模块的内的代码了

可以在一行导入多个模块
import spam,m1,m2,m3  # 不推荐
如果导入的模块名过长可以修改它的名称
import spamasdfasfsadfadfasfd as sm
sm.xxx
(2)from...import...as...

ps:大部分情况下我们的python程序不应该使用这种导入方式,因为*你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字。而且可读性极其的差,在交互式环境中导入时没有问题

_all_=['money','read1'] # 这样在另外一个文件中用from spam import *就这能导入列表中规定的两个名字

上一篇 下一篇

猜你喜欢

热点阅读