函数递归调用(二分法),三元表达式,匿名函数,模块

一、函数递归调用

1、函数的递归调用:就是在调用一个函数的过程中又直接或间接地调用自己
  ps:嵌套调用自己
  示例1:直接调用自己
def foo():
      print('hello')
      foo()
foo()
  示例2:间接调用自己
def bar():
    print('from bar')
    foo()

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

foo()
为何递归会抛出异常???
因为无限的递归会导致内存溢出,所以python设定了最大的递归层数
import sys
print(sys.getrecursionlimit())#查看递归层数
print(sys.setrecursionlimit(2000))#设置最大递归层数
所以:不应该无限递归调用下去,应该在满足某种条件下结束递归调用,然后返回

2、递归调用应该分为两个阶段
  (1)回溯(挖井)        :一层一层地递归调用下去
(2)递推(从井里往外跳):在满足某一条件的情况下结束回溯,然后开始向上一层层返回
#案例:关于一层层得到某人薪资
'''
分析 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)
#案例:取出列表中每个值
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)

#(二分法)案例:从小到大排列的一个数字列表

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)

二、三元表达式

    基本语法:表达式1 if 条件 else 表达式2

#原始写法
def max(x,y):
    if x > y:
        return x
    else:
        return y
max(1,2)
#利用三元表达式:更加简洁方便
x=111
y=222
res=x if x > y else y
print(res)

   三元表达式:让代码变得清晰简洁

三、匿名函数

匿名函数即没有名字的函数
基本语法:返回值=(lambda 形参,形参... : 返回值)(传实参,传实参...)
res =(lambda x,y:x+y)(1,2)
#利用匿名函数
res=(lambda x,y:x+y)(1,2)
print(res)
#不要用以下方式写,就像于绕了一圈,无意义
f = lambda x, y: x + y
print(f)
f(1, 2)
特点:没有名字意味着只能用一次,用完之后就是垃圾,所以匿名函数只用于临时使用一次的场景,一般跟其他函数配合使用

#案例(字典取值相关)
salaries = {
    'egon': 4.4,
    "lqz": 3.3,
    'yj': 2.2
}

# def func(k):
#     return salaries[k]
#用max求最高薪资的人
print(max(salaries, key=lambda k:salaries[k]))

#用min求最低薪资的人
print(min(salaries, key=lambda k:salaries[k]))

#用sorted按从小到大排序,默认reverse=False,也可以不写,默认sorted就是按照从小到大排序的
print(sorted(salaries,key=lambda k:salaries[k],reverse=False))
#用sorted按从大到小排序,默认reverse=False,利用reverse=True翻转 print(sorted(salaries,key=lambda k:salaries[k],reverse=True))

四、模块

1、什么是模块
模块就是一个功能的集合体,不是用来直接运行,而是用来被导入使用的
模块分为三大来源:
1、内置的模块
2、第三方模块
3、自定义的模块
模块分为四种类别:
1、一个py文件就是一个模块
2、一个文件夹也是一个模块=》包
3、已被编译为共享库或DLL的C或C++扩展(不常用)
4 使用C编写并链接到python解释器的内置模块(不常用)

2、为何要用模块
使用别人的模块:
1、拿来主义,提升开发效率
自定义模块:
1、别人的功能不够用了,需要自己的去编写
2、解决代码冗余

3、如何用模块
#建文件run1.py ,run2.py , spam.py 利用run1.py run2.py调用spam.py的功能
#文件run.py 利用import spam
ps:文件名有.py  模块名是去掉.py
# 文件名是spam.py,模块名则是spam
x=111

import spam
# 首次导入模块发生的事情
# 1、触发被导入的模块的运行,产生一个模块的名称空间,把模块中的名字都丢进去
# 2、会在当前执行文件中得到一个名字spam,该名字是指向被导入模块的名称空间的

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

money = 2000


# print(money)
# print(spam.money)

# spam.read1()

# def read1():
#     print('run1.py----read1')

# spam.read2()
# spam.change()
# print(spam.money)
# print(money)


# 一行导入多个模块
import spam,m1,m2,m3  # 名字之间用,分隔开 不推荐

# 为导入的模块起别名
# import spamasdfasfsadfadfasfd as sm
# sm.xxx
# 示例:
# #mysql.py
# def sqlparse():
#     print('from mysql sqlparse')
# #oracle.py
# def sqlparse():
#     print('from oracle sqlparse')
#
# #test.py
# db_type=input('>>: ')
# if db_type == 'mysql':
#     import mysql as db
# elif db_type == 'oracle':
#     import oracle as db
#
# db.sqlparse()

#文件run2.py 利用 import spam import spam里的具体功能

# 文件名是spam.py,模块名则是spam
x=111
# from spam import money,read1,read2  # money=spam.money,read1=spam.read1,read2=spam.read2
# 首次导入模块发生的事情
# 1、触发被导入的模块的运行,产生一个模块的名称空间,把模块中的名字都丢进去
# 2、会在当前执行文件中得到名字
#    money=模块spam中的money对应值的内存地址
#    read1=模块spam中的read1对应值的内存地址
#    read2=模块spam中的read2对应值的内存地址


# from spam import money,read1,read2
# from spam import money,read1,read2
# from spam import money,read1,read2
# from spam import money,read1,read2

# print(money)
# print(read1)
# print(read2)


# money=111
# print(money)

# money=2000
# read1()

# def read1():
#     print('run.py read1')
# read2()


# 一行导入多个名字
# from spam import money,read1


# 为导入的模块起别名
# from spam import money as m
#
# print(m)

# from spam import *#导入spam文件的所有功能,但是如果在spam文件开头有__all__[用列表或元组,这里面写的是名字]的话,只能调用指定范围内的功能;这样在另外一个文件中用from spam import *就这能导入列表/元组中开放的两个名字
 from spam import * # print(money) # print(read1) # print(read2) print(change)

#文件spam

# spam.py
print('from the spam.py')

__all__ = ['money', 'read1']#让*只能导入指定函数

money = 1000

def read1():
    print('spam模块:', money)

def read2():
    print('spam模块')
    read1()

def change():
    global money
    money = 0
ps:只要一导入一个文件,那么被导入的那个文件就会运行,只要一运行一个文件,就会造一个全局名称空间,把运行过程中产生的名字都丢进去。
小结:
#1
import spam
spam.xxx
不会跟当前名称空间里的冲突
每次用名字都要加前缀spam.
#1
from spam import xxx
xxx
容易跟当前名称空间的冲突,名字容易被覆盖,容易搞混
尽量不要循环导入
原文地址:https://www.cnblogs.com/guojieying/p/13366582.html