一.函数递归

  函数的递归调用:是函数嵌套调用的一种特殊形式

  具体指的是在调用一个函数的过程中又直接或者间接地调用自己,称之为函数的递归调用

  函数的递归调用其实就是用函数实现的循环
# def f1():
#     print('from f1')
#     f1()
 
# f1()

或者

# def f1():
#     print('f1')
#     f2()
#
# def f2():
#     print('f2')
#     f1()
#
# f1()
一个递归的过程应该分为两个阶段:
 1、回溯:向下一层一层调用
 2、递推:向上一层一层返回 
#1

# age(5) = age(4) + 10
# age(4) = age(3) + 10
# age(3) = age(2) + 10
# age(2) = age(1) + 10
#
# age(1) = 18
#
# n > 1 -> age(n) = age(n-1) + 10
# n = 1 -> age(1) = 18
 
# def age(n):
#     if n == 1:
#         return 18
#     return age(n-1) + 10
#
# res = age(5)
# print(res)
 
#2 
# nums = [1,[2,[3,[4,[5,[6,[7,[8,]]]]]]]]
#
# def func(nums):
#     for item in nums:
#         if type(item) is list:
#             func(item)
#         else:
#             print(item)
#
# func([1,[2,[3,[4,[5,[6,[7,[8,]]]]]]]])
 
 
 #3
nums = [-3,1,5,7,9,11,13,18,22,38,78,98]
 
 
# for num in nums:
#     if num == find_num:
#         print('find it')
#         break
 
def search(find_num,nums):
    print(nums)
    if len(nums)  == 0:
        print('not exists')
        return
    mid_index = len(nums) // 2
    if find_num > nums[mid_index]:
        # in the right
        new_nums = nums[mid_index+1:]
        search(find_num,new_nums)
    elif find_num < nums[mid_index]:
        # in the left
        new_nums = nums[:mid_index]
        search(find_num,new_nums)
    else:
        print('find it')
 
# search(22,nums)
search(23,nums)

二.匿名函数

对比使用def关键字创建的是有名字的函数,使用lambda关键字创建则是没有名字的函数,即匿名函数,语法如下

# 1、定义
lambda x,y,z:x+y+z

#等同于
def func(x,y,z):
    return x+y+z

# 2、调用
# 方式一:
res=(lambda x,y,z:x+y+z)(1,2,3)

# 方式二:
func=lambda x,y,z:x+y+z # “匿名”的本质就是要没有名字,所以此处为匿名函数指定名字是没有意义的
res=func(1,2,3)

   匿名函数与有名函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放,所以匿名函数用于临时使用一次的场景,匿名函数通常与其他函数配合使用

#取得薪水的最大值和最小值
salaries={
    'siry':3000,
    'tom':7000,
    'lili':10000,
    'jack':2000
}

# 函数max会迭代字典salaries,每取出一个“人名”就会当做参数传给指定的匿名函数,然后将匿名函数的返回值当做比较依据,最终返回薪资最高的那个人的名字
>>> max(salaries,key=lambda k:salaries[k]) 
'lili'
# 原理同上
>>> min(salaries,key=lambda k:salaries[k])
'jack'

三.map、reduce、filter

  函数map、reduce、filter都支持迭代器协议,用来处理可迭代对象,我们以一个可迭代对象array为例来介绍它们三个的用法

array=[1,2,3,4,5]

1.map

要求一:对array的每个元素做平方处理,可以使用map函数
map函数可以接收两个参数,一个是函数,另外一个是可迭代对象,具体用法如下
>>> res=map(lambda x:x**2,array)
>>> res
<map object at 0x1033f45f8>
>>>
解析:map会依次迭代array,得到的值依次传给匿名函数(也可以是有名函数),而map函数得到的结果仍然是迭代器。
>>> list(res) #使用list可以依次迭代res,取得的值作为列表元素
[1, 4, 9, 16, 25]

2.reduce

要求二:对array进行合并操作,比如求和运算,这就用到了reduce函数
reduce函数可以接收三个参数,一个是函数,第二个是可迭代对象,第三个是初始值
# reduce在python2中是内置函数,在python3中则被集成到模块functools中,需要导入才能使用
>>> from functools import reduce 
>>> res=reduce(lambda x,y:x+y,array)
>>> res
15
解析:1 没有初始值,reduce函数会先迭代一次array得到的值作为初始值,作为第一个值数传给x,然后继续迭代一次array得到的值作为第二个值传给y,运算的结果为3
2 将上一次reduce运算的结果作为第一个值传给x,然后迭代一次array得到的结果作为第二个值传给y,依次类推,知道迭代完array的所有元素,得到最终的结果15
也可以为reduce指定初始值
>>> res=reduce(lambda x,y:x+y,array,100)

>>> res
115

3.filter

要求三:对array进行过滤操作,这就用到了filter函数,比如过滤出大于3的元素
>>> res=filter(lambda x:x>3,array)
解析:filter函数会依次迭代array,得到的值依次传给匿名函数,如果匿名函数的返回值为真,则过滤出该元素,而filter函数得到的结果仍然是迭代器。
>>> list(res) 
[4, 5]

 提示:我们介绍map、filter、reduce只是为了带大家了解函数式编程的大致思想,在实际开发中,我们完全可以用列表生成式或者生成器表达式来实现三者的功能。 

四.模块

1、什么是模块
    模块就是一系列功能的集合体
    模块分为四种类别:
        1、一个py文件就可以是一个模块
        2、包:就是一个存放有__init__.py文件的文件夹
 
        3、使用C编写并链接到python解释器的内置模块
        4、已被编译为共享库或DLL的C或C++扩展
 
    模块有三种来源
        1、python解释器自带的
            内置的
            标准库
            import time  # 内置库
            print(time)
            import os  # 标准库
            print(os)
 
        2、第三方的库
        3、自定义的库
2、为何要用模块
    1、拿来主义,极大地提升开发效率
    2、解决代码冗余问题
 
3、模块用法
1.import
import foo #导入模块foo
a=foo.x #引用模块foo中变量x的值赋值给当前名称空间中的名字a
foo.get() #调用模块foo的get函数
foo.change() #调用模块foo中的change函数
obj=foo.Foo() #使用模块foo的类Foo来实例化,进一步可以执行obj.func()
  #加上foo.作为前缀就相当于指名道姓地说明要引用foo名称空间中的名字,所以肯定不会与当前执行文件所在名称空间中的名字相冲突,并且若当前执行文件的名称空间中存在x,执行foo.get()或foo.change()操作的都是源文件中的全局变量x。  
  #需要强调一点是,第一次导入模块已经将其加载到内存空间了,之后的重复导入会直接引用内存中已存在的模块,不会重复执行文件,通过import sys,打印sys.modules的值可以看到内存中已经加载的模块名。# 后续的导入直接引用首次导入的成果
 
   #首次导入模块发生三件事
   1、会触发spam.py运行,所以会产生一个模块的名称空间
   2、运行spam.py的代码,将运行过程中产生的名字都丢到模块的名称空间中
   3、在当前执行文件的名称空间中拿到一个名字spam,该名字就是指向模块的名称空间的

2.from-import 语句

from...import...与import语句基本一致,唯一不同的是:使用import foo导入模块后,引用模块中的名字都需要加上foo.作为前缀,而使用from foo import x,get,change,Foo则可以在当前执行文件中直接引用模块foo中的名字,如下

from foo import x,get,change #将模块foo中的x和get导入到当前名称空间
a=x #直接使用模块foo中的x赋值给a
get() #直接执行foo中的get函数
change() #即便是当前有重名的x,修改的仍然是源文件中的x

3.其它

(1)  *

from foo import * #把foo中所有的名字都导入到当前执行文件的名称空间中,在当前位置直接可以使用这些名字

a=x
get()
change()
obj=Foo()

(2)as

#为导入的模块起别名
import foo as f #为导入的模块foo在当前位置起别名f,以后再使用时就用这个别名f
f.x
f.get()

#为导入的名字起别名
from foo import get as get_x
get_x()

4.循环导入问题

详见: https://zhuanlan.zhihu.com/p/109127048 

5.搜索模块的路径与优先级

     在导入一个模块时,如果该模块已加载到内存中,则直接引用,否则会优先查找内置模块,然后按照从左到右的顺序依次检索sys.path中定义的路径,直到找模块对应的文件为止,否则抛出异常。sys.path也被称为模块的搜索路径,它是一个列表类型

>>> sys.path
['',
'/Library/Frameworks/Python.framework/Versions/3.5/lib/python35.zip',
'/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5',
...,
'/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages'

6. 区分py文件的两种用途

一个Python文件有两种用途:

   (1)一种被当主程序/脚本执行

   (2)另一种被当模块导入

   #为了区别同一个文件的不同用途,每个py文件都内置了__name__变量,该变量在py文件被当做脚本执行时赋值为“__main__”,在py文件被当做模块导入时赋值为模块名

 

posted on 2021-03-31 17:06  lzl_121  阅读(51)  评论(0编辑  收藏  举报