二分法
需求:有一个按照从小到大顺序排列的数字列表,找到目标数字,如果目标数字不在列表,打印不存在
nums = [1, 3, 5, 11, 20, 22, 35, 36, 37, 40, 45, 46,57,84,93,99,101,156]
def binary_search(find_num, nums):
print(nums) #每轮都打印列表,以观察列表的变化
if not nums == []: #判断列表是否为空,不为空才可以进行比较
mid_val = (nums[len(nums)//2]) #找到列表的中间值,利用列表长度/2作为索引
if find_num > mid_val:
num = nums[len(nums)//2+1:] #如果目标值比中间值大,说明目标值在中间的右边,就切分列表,由中间值+1的索引,到最尾的值
binary_search(find_num, num) #利用递归的思想,将上诉操作重复
elif find_num < mid_val:
num = nums[0:len(nums)//2]#如果目标值比中间值小,说明目标值在中间的左边,就切分列表,由中间值的索引,到最首端的值
binary_search(find_num, num)
elif find_num == mid_val:
print("找到了")
else:
print('找不到') ##如果列表为空,就可以判定,此目标数字不在列表中
binary_search(99, nums)
binary_search(66, nums)
'''
[1, 3, 5, 11, 20, 22, 35, 36, 37, 40, 45, 46, 57, 84, 93, 99, 101, 156]
[45, 46, 57, 84, 93, 99, 101, 156]
[99, 101, 156]
[99]
找到了
[1, 3, 5, 11, 20, 22, 35, 36, 37, 40, 45, 46, 57, 84, 93, 99, 101, 156]
[45, 46, 57, 84, 93, 99, 101, 156]
[45, 46, 57, 84]
[84]
[]
找不到
'''
编程思想 / 范式
面向过程的编程思想:
核心是“过程”二字,过程即流程,指的是做事的步骤:先什么、再什么、后干什么
基于该思想编写程序就好比在设计一条流水线
优点:复杂的问题流程化、进而简单化
缺点:扩展性非常差(比如生产瓶装饮料的流水线,要想改成生产易拉罐饮料,就需要处处修改流水线)
匿名函数lambda
- 有些函数在代码中只用一次,而且函数体比较简单,使用匿名函数可以减少代码量,看起来比较"优雅“
匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果:
lambda 参数: 表达式
用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数:
res=(lambda x,y:x+y)(1,2)
print(res)
如何调用匿名函数
看案例:
找出薪资最高的那个人:
salaries = {
'siry': 2000,
'tom': 7000,
'lili': 10000,
'jack': 200
}
max( )方法,可以用来比较薪资
但是如果直接将字典放入,只会返回key中字符最大的,而不是薪资,需要更改比较依据
max(salaries,key=...)
所以key后面应该是薪资,用往常的方法,创建一个有名函数
def func(k):def func(k):
return salaries[k]
salaries = {
'siry': 2000,
'tom': 7000,
'lili': 10000,
'jack': 200
}
# 找出薪资最高的那个人
res=max(salaries, key=func)
print(res)
'''
lili
'''
如果运用匿名函数:
salaries = {
'siry': 2000,
'tom': 7000,
'lili': 10000,
'jack': 200
}
# 找出薪资最高的那个人
res=max(salaries,key=lambda k:salaries[k])
print(res)
'''
lili
'''
模块
模块就是一系列功能的集合体,分为三大类
- 内置模块
- 第三方模块
- 自定义的模块:一个python文件本身就是一个模块,文件名m.py,模块名叫m
为何要用模块?
- 内置和第三方模块,拿来就用,无需定义,可以极大地提升自己的开发效率
- 自定义模块,可以将程序的各部分功能提取出来放到一模块中为各个文件共享使用,好处是减少了代码冗余,程序组织结构更加清晰
如何用模块
首次导入模块会发生三件事:
- 执行foo.py
- 产生foo.py的名称空间,将运行过程中产生的名字都丢到foo的名称空间中
- 在当前文件的名称空间中产生一个名字foo,该名字指向foo文件中的名称空间
新建文件foo.py,写下以下代码:
print('foo模块')
def func1():
print('form func1')
print(x)
def func2():
print('form func2')
x=1
在另外的文件导入该文件
import foo
import foo
'''
foo模块
'''
之后的导入,都是直接引用首次导入产生的foo.py名称空间,不会重复执行代码
引用
模块名.名字 指名道姓地问某一个模块要名字对应的值,不会与当前文件的名称发生冲突
import foo
print(foo.x)
print(foo.func1)
'''
foo模块
1
<function func1 at 0x00000124D1310DC0>
'''
强调:无论是查看还是修改都是原模块本身,与调用位置无关
import foo
x=3333333
foo.func1()
'''
foo模块
form func1
1
'''
强调2:可以以逗号为分隔符在一行导入多个模块,但是不建议这样做
import time,foo,...
建议一行导入一个模块,并且运用以下的导入模块顺序
- python内置模块
- 第三方模块
- 自定义模块
import time
import sys
import 第三方
import 第三方
import 自定义
import 自定义
...
import … as … 给模块起另一个名字,适用于一些第三方模块名字过长
py文件的两种用途
- 当做程序被运行
- 当做模块被导入
执行文件在运行的时候会产生执行文件的名称空间,并将程序运行过程中产生的名字存放到执行文件的名称空间。
如果执行文件中有导入模块的操作,import foo(模块名)会将模块名存放到执行文件的名称空间,执行文件的模块名指向的就是被导入模块的名称空间。
导入模块会执行被导入的模块文件,产生被导入模块的名称空间,执行过程中产生的名字存放到被导入模块的名称空间,并存放到内存的内置模块中提供给执行文件使用,当执行文件运行完毕后,导入模块的文件才会跟着结束。
一个Python文件有两种用途,一种被当主程序/脚本执行,另一种被当模块导入,为了区别同一个文件的不同用途,
每个py文件都内置了__name__变量,该变量在py文件被当做脚本执行时赋值为“main”,在py文件被当做模块导入时赋值为模块名
if __name__ == '__main__':
print('我被执行了') 导入模块自己执行会打印
else:
print('我被导入了') 执行文件导入该模块会被打印
本小节内容来源于:python文件的两种用途与区别
from … import …
在上述的中学习到的import,在导入模块之后,如果要使用模块,必须要加前缀’‘模块.xxx’’
优点:肯定不会与当前名称空间中的名字冲突
缺点:加前缀显的麻烦
#foo模块
print('foo模块')
def func1():
print('form func1')
print(x)
def func2():
print('form func2')
x = 1
from foo import x #x是当前文件的名称空间,当时内存地址指向的是foo模块中的x内存地址
from foo import func1 #同理
from foo import func2 #同理
from … import …导入也发生了三件事:
1、产生一个模块的名称空间
2、运行foo.py将运行过程中产生的名字都丢到模块的名称空间中
3、在当前名称空间拿到一个名字,该名字与模块名称空间中的某一个内存地址相同
导入模块时,名称空间的查找,也是在函数定义阶段找:
from foo import func1
x=333333
func1()
'''
foo模块
form func1
1
'''
优点:可以简化代码
缺点:容易混淆名字
#foo
#x=1
from foo import x
x=11111
print(x)
'''
x=1
x=11111
'''
容易将值在无意中就改变了
循环导入问题
就是两个模块相互导入了对方,比如:
m1:
print('正在导入m1')
form m2 import y
x='m1'
m2:
print('正在导入m2')
form m1 import x
y='m2'
import m1
一旦直接运行,直接报错
分析原因
首先导入了m1,本身应该会做三件事情
- 执行m1.py
- 产生m1.py的名称空间,将运行过程中产生的名字都丢到m1的名称空间中
- 在当前文件的名称空间中产生一个名字m1,该名字指向m1文件中的名称空间
但是但是在运行到第二行时,又导入了m2,就进入到了m2的文件中,重新做上面三件事情,也是在运行到第二行的时候,遇到了from m1 import x
,由于m1已经被导入过一次,所以不会再重新产生一个新的名称空间,而是到原本的名称空间中,去寻找x,但是此时,m1的名称空间中并没有产生x的名字,因为再产生x之前就遇到了from m2 import y
,还没来得及产生x,所以报错。
解决方法一:将需要的名字都在导用之前先定义好
m1:
print('正在导入m1')
x='m1'
form m2 import y
m2:
print('正在导入m2')
y='m2'
form m1 import x
解决方法二:利用函数不调用就不会执行的方式来解决
m1:
print('正在导入m1')
def func1():
form m2 import y
print(y)
x='m1'
m2:
print('正在导入m2')
def func2():
form m1 import x
print(x)
y='m2'