文章目录
一、函数的递归调用
(一)什么是函数的递归调用
就是函数在调用过程中,直接或间接的调用了自己。为防止内存溢出,在python中函数的递归调用默认最大1000层。所以函数递归不应无限进行,应在满足某条件时结束,然后返回。
# 直接调用自己
def func():
print('from func')
func()
func()
# 间接调用自己
def foo():
print('from foo')
bar()
def bar():
print('from bar')
foo()
foo()
(二)递归的两个阶段
1.回溯:
一层层地回溯下去。
2.递推:
在满足某条件的情况下结束回溯,然后一层层向上返回。
# 案例:
# 某公司四个员工坐在一起,问第四个人薪水,他说比第三个人多1000,问第三个人薪水,第他说比第二个人多1000,问第二个人薪水,他说比第一个人多1000,最后第一人说自己每月5000,请问第四个人的薪水是多少?
# 思路解析:
# 要知道第四个人的月薪,就必须知道第三个人的,第三个人的又取决于第二个人的,第二个人的又取决于第一个人的,而且每一个员工都比前一个多一千,数学表达式即:
salary(4)=salary(3)+1000
salary(3)=salary(2)+1000
salary(2)=salary(1)+1000
salary(1)=5000
总结为:
salary(n)=salary(n-1)+1000 (n>1)
salary(1)=5000 (n=1)
# 代码实现
def salary(n):
if n==1:
return 5000
return salary(n-1) + 1000
s = salary(4)
print(s) # 8000
# 打印列表里的所有值:
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)
# [11, 13, 32, 47, 53, 73, 84, 91, 101, 111, 222, 333, 444, 5555]
# [11, 13, 32, 47, 53, 73, 84]
# [53, 73, 84]
# [84]
# []
# find_num not exists
二、三元表达式
二、三元表达式
(一)什么是三元表达式
三元表达式是一种可以简化代码的方式,在不丧失可读性的情况下,精简代码。
# 表达式1 if 条件 else 表达式2
# 将三元表达式赋值给一个变量,可以得出结果
(二)如何使用三元表达式
# 案例
x = 111
y = 222
def max2(x, y):
if x > y:
return x
else:
return y
res = x if x > y else y # 一行代码搞定一个简单的比较取值过程
print(res) # 222
三、匿名函数
(一)什么是匿名函数
匿名函数就是没有名字的函数。
没有名字意味着只能使用一次,用完之后就是垃圾,所以匿名函数只能用于临时使用一次的场景。
匿名函数的表达式:lambda 参数:表达式 ===>>> 进而得出结果
表达式 lambda parameters: expression 会产生一个函数对象。
该未命名对象的行为类似于用以下方式定义的函数:
def <lambda>(parameters):
return expression
(二)如何使用匿名函数
# 错误示范:给匿名函数命名(没有意义)
res = lambda x, y: x + y
print(res(1, 2))
# 正确用法:
res = (lambda x, y: x + y)(1, 2)
print(res)
# 用于使用一次就没作用的场景,如:为其他函数作为一个辅助参数
salaries = {
'egon': 4.4,
"lqz": 3.3,
'yj': 2.2
}
# max()、min()、sorted()函数对字典默认针对key进行排序,若要对值进行排序并返回key,可以加一个参数key,作为实际比较的依据。
res = max(salary, key=lambda k: salary[k])
print(res) # egon
res = min(salary, key=lambda k: salary[k])
print(res) # yj
res = sorted(salary, key=lambda k: salary[k], reverse = True)
print(res) # ['egon', 'lqz', 'yj']
res = sorted(salary, key=lambda k: salary[k])
print(res) # ['yj', 'lqz', 'egon']
四、模块介绍
(一)什么是模块
1.模块的定义:
模块就是一个功能的集合体,不是用来直接运行的,而是用于被导入使用的。
2.模块的三个来源:
(1)python内置模块;(2)第三方模块;(3)自定义模块。
3.模块的四个类型:
(1)一个py文件就是一个模块;(2)一个文件夹(包)也是一个模块;(3)已被编译为共享库或DLL的DLL的C或C++扩展:(4)使用C语言编写并链接到python解释器的内置模块。
(二)为何使用模块
1.使用别人的模块:
拿来主义,提升开发效率。
2.使用自定义模块:
为了减少代码冗余,方便程序的组织、管理。
五、模块的使用
(一)模块使用之import语句
1.import的使用
# 以spam.py为例
print('from the spam.py')
money=1000
def read1():
print('spam模块:',money)
def read2():
print('spam模块')
read1()
def change():
global money
money=0
# test.py
import spam #只在第一次导入时才执行spam.py内代码,此处的显式效果是只打印一次'from the spam.py'(spam.py文件中的可执行语句),当然其他的顶级代码也都被执行了,只不过没有显示效果.
import spam
import spam
import spam
'''
执行结果:
from the spam.py
'''
2.首次导入模块发生了三件事
若重复导入会直接引用内存中已加载好的结果。
(1)为源文件(如:spam模块)创建新的名称空间,在spam中定义的函数和方法都在这个名称空间中,如果发生全局调用,则使用的数据也是该名称空间中的。
(2)在新创建的名称空间的同时执行模块中包含的代码,即在import spam 代码写完的同时触发运行。
(3)在当前名称空间中创建名字spam来引用该名称空间中的内容。
3.被导入的模块有独立的名称空间
每个模块都是一个独立的名称空间,定义在这个模块中的函数,把这个名称空间当作全局名称空间,这样就不会让被导入的模块与使用者的全局变量冲突。
(1)测试一:money与spam.money不冲突
# test.py
import spam
money=10
print(spam.money)
'''
执行结果:
from the spam.py
1000
'''
(2)测试二:read1与spam.read1不冲突
# test.py
import spam
def read1():
print('========')
spam.read1()
'''
执行结果:
from the spam.py
spam->read1->money 1000
'''
(3)测试三:执行spam.change()操作的全局变量money仍然是spam中的
# test.py
import spam
money=1
spam.change()
print(money)
'''
执行结果:
from the spam.py
1
'''
4.为模块起别名
可以为导入的模块起别名,简化调用的复杂程度。
import spam as sm
print(sm.money)
有两种sql模块mysql和Oracle,根据用户的输入,选择不同的sql功能
#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()
5.可以一行导入多个模块
import sys,os,re
(二)模块使用之from-import 语句
1.from…import…的使用
from spam import read1, read2
2.from…import 与import的对比
不同:使用from…import…语句,是将spam中的名字直接导入当前名称空间,使用名字的时候不用加spam.进行调用了。
优势:使用起来更方便。
劣势:容易与当前执行文件中的名字冲突,相同名字的数据有覆盖效果。
(1)验证一:当前位置直接使用read1和read2就好了,执行时,仍然以spam.py文件全局名称空间
#测试一:导入的函数read1,执行时仍然回到spam.py中寻找全局变量money
#test.py
from spam import read1
money=1000
read1()
'''
执行结果:
from the spam.py
spam->read1->money 1000
'''
#测试二:导入的函数read2,执行时需要调用read1(),仍然回到spam.py中找read1()
#test.py
from spam import read2
def read1():
print('==========')
read2()
'''
执行结果:
from the spam.py
spam->read2 calling read
spam->read1->money 1000
'''
(2)验证二:如果当前有重名read1或者read2,那么会有覆盖效果。
#测试三:导入的函数read1,被当前位置定义的read1覆盖掉了
#test.py
from spam import read1
def read1():
print('==========')
read1()
'''
执行结果:
from the spam.py
==========
'''
(3)验证三:导入的方法在执行时,始终是以源文件为准的
from spam import money,read1
money=100 #将当前位置的名字money绑定到了100
print(money) #打印当前的名字
read1() #读取spam.py中的名字money,仍然为1000
'''
from the spam.py
100
spam->read1->money 1000
'''
3.支持as为模块起别名
from spam import read1 as read
4.支持一行导入多个名字
from spam import read1,read2,money
5.from…import * 的是使用
# from spam import * 把spam中所有的不是以下划线(_)开头的名字都导入到当前位置
# 大部分情况下我们的python程序不应该使用这种导入方式,因为*你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字。而且可读性极其的差,在交互式环境中导入时没有问题。
from spam import * #将模块spam中所有的名字都导入到当前名称空间
print(money)
print(read1)
print(read2)
print(change)
'''
执行结果:
from the spam.py
1000
<function read1 at 0x1012e8158>
<function read2 at 0x1012e81e0>
<function change at 0x1012e8268>
'''
可以使用__ all __来控制*(用来发布新版本),在spam.py中新增一行:
__all__=['money','read1'] #这样在另外一个文件中用from spam import *就这能导入列表中规定的两个名字
)开头的名字都导入到当前位置
大部分情况下我们的python程序不应该使用这种导入方式,因为*你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字。而且可读性极其的差,在交互式环境中导入时没有问题。
```python
from spam import * #将模块spam中所有的名字都导入到当前名称空间
print(money)
print(read1)
print(read2)
print(change)
'''
执行结果:
from the spam.py
1000
<function read1 at 0x1012e8158>
<function read2 at 0x1012e81e0>
<function change at 0x1012e8268>
'''
可以使用__ all __来控制*(用来发布新版本),在spam.py中新增一行:
__all__=['money','read1'] #这样在另外一个文件中用from spam import *就这能导入列表中规定的两个名字