python2.0 s12 day4
04 python s12 day4 TengLan回顾上节内容
05 python s12 day4 迭代器原理及使用
本节大纲介绍:
1.迭代器&生成器
2.装饰器
1.基本装饰器
2.多参数装饰器
3.递归
4.算法基础:二分查找 二维数组转换
5.正则表达式
6.常用模块学习
7.作业
1.迭代器&生成器
1)迭代器
定义:
就是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.
优点:
不需要事先准备好整个迭代过程中所有的元素.仅仅在迭代到某一个元素时,才在内存中创建该元素,在迭代之前或者之后,元素可以不存在,或者被销毁.
这个优点使得它特别适合用于便利一些巨大的或者时无限的集合.比如几个G的文件.
特性:
1).访问者不需要关心迭代器内部的结构,仅需要通过__next__()方法不断去取下一个内容.
2).不能随机访问集合中的某个值,只能从头到尾依次访问.列表就可以.
3).迭代器只能往前不会后腿,不过也没什么,因为人吗很少在迭代器中后退.
4).便于循环比较大的数据集合,节省内存
迭代器实际实例:
1).在Linux环境下,你用vim编辑器打开一个几个G的文件,就需要把文件内容加载到内存中,光打开的时间可能是3分钟.
当你cat时,可能几秒钟就显示完了,即使你看不清,它也显示完了,同时你也不能在cat时,跳到中间或者其他位置.cat就是迭代器实现的.
2)文件打开方法open
f = open("1.txt",'r')创建一个文件句柄.
>>> f.read() #读取文件所有行以字符串形式
'import sys\n\nimport sys as sss\nprint sys.argv\nprint sys.argv[2]\nfrom sys import argv \nfrom sys import *\n'
>>> f.seek(0)
0
>>> f.readlines() #读取文件所有行,以列表形式
['import sys\n', '\n', 'import sys as sss\n', 'print sys.argv\n', 'print sys.argv[2]\n', 'from sys import argv \n', 'from sys import *\n']
>>>
f.read() 和 f.readlines()都不是迭代的形式,f是迭代器,所以以后读文件时,不要用f.read()和f.readlines()
迭代器的创建方法:
>>> name = iter(["alex","jack","list"])
>>> name
<list_iterator object at 0x101815898> #list_iterator 是列表迭代器
>>> name = iter(("alex","jack","list"))
>>> name
<tuple_iterator object at 0x101a04780> #tuple_iterator 元组迭代器
>>> name[1] #迭代器不能用下标查找了,只能循环迭代
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple_iterator' object is not subscriptable
>>> name.__next__() #只能用__next__()方法获取下一个值
'alex'
>>> name.__next__()
'jack'
>>> name.__next__()
'list'
迭代器只有这个__next__()方法,不能对这个迭代器进行统计数量
>>> len(name)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'tuple_iterator' has no len()
>>>
06 python s12 day4 生成器的使用
2)生成器
定义:
还是一个函数,调用的时候返回的不是一个值,而是一个迭代器。
如果一个函数调用时反回一个迭代器,那这个函数就是生成器。
那么怎么才能让一个函数返回一个迭代器呢,那么就要使用yield语法。
如果一个函数有yield 语法那么这个函数就是一个生成器。
生成器的实际意义:
1.普通函数,你在调用的时候,执行后返回值。假如函数逻辑复杂,好多东西要执行,就需要很长时间。那么你调用的时候是不是要等着。那么生成器就出场了。你调用生成器函数。立马返回一个迭代器。
当我要调用一个接口,接口需要执行很长时间,那我就不等它调用执行完成,先去干其他的事情。从而实现了异步。
返回的迭代器,迭代器的作用就是记录函数执行的位置。
生成器的实际实例:
#!/usr/bin/env python
#__*__encoding:utf-8__*__
def cash_money(amount):
while amount > 0:
amount -= 100
yield 100
print('又来取钱了!')
fun1 = cash_money(500)
print(type(fun1))
#使用fun1.__next__()获取生成器中的下一个迭代项.python2.0中方法不是私有的即fun1.next()
print(fun1.__next__())
print(fun1.__next__())
print("大保健") 寒素执行到yield时,干了一件"大保健"事.
print(fun1.__next__()) 大保健完事,又去取钱
print(fun1.__next__())
print(fun1.__next__())
#yield 实现了两大特点,1一个函数多次执行.2.从未循环完的while语句中跳了出来.
07 python s12 day4 使用yield实现单线程中的异步并发效果
断点执行演示:
略
深入思考(问题来了):
1.能不能往__next__()传参数,每次取不同的钱数.答案通过__next__()不能传参数.
2.如果是去银行取钱,银行审核用了2天,审核结果是我不停的去问还是银行处理完后告诉我,最好是处理完告诉我,那这就是异步,那怎么实现呢.
在串行的程序中实现异步效果.
问题1.每次取钱时能输入参数,解决方案:通过python新语法send()语法
#!/usr/bin/env python3.5
def cash_money(amount):
while amount > 0:
money = yield
amount -= int(money)
print("你取了%s元,还有余额%s元"%(money,amount))
fun1 = cash_money(500)
#print(type(fun1))
fun1.__next__() #这里一定要先调用fun1.__next__()方法,才能让迭代器走到yield代码处
money2 = input("输入取款金额:")
fun1.send(money2) #新语法,把money2发给fun1这个迭代器,yield接收这个值,并且继续执行下面的代码
问题2解决方案:yield异步
生产crm.oldboyedu.com者,消费者模型
拿吃包子和做包子举例:
#定义一个吃包子
def consumer(name):
print("%s 准备吃包子啦")%name
while True:
baozi = yield
print("包子[%s]来了,被[%s]吃了")%(baozi,name)
def producer(name):
c = consumer("A")
c2 = consumer('B')
c.__next__()
c2.__next__()
print("老子开始准备做包子啦!")
for i in range(10):
time.sleep(1)
print("做了2哥包子")
c.send(i) #新语法,把i发给c这个迭代器,这时yield接收这个值,并且继续执行下面的代码
c2.send(i) #同上
producer("alex")
08 python s12 day4 装饰器原理介绍和基本实现
09 python s12 day4 装饰器实现
10 python s12 day4 实现带参数的复杂装饰器
此3节用s11期的代替:
python装饰器原理一
必备知识:
定义一个函数:
#/usr/bin/env python3.5
#假设这个文件名称为index.py那么执行用./index.py
def foo():
print("foo")
foo() #表示执行函数
foo # 表示是函数
我们都知道,当我们执行index.py时,首先将文件读入内存,然后python解释器去解释.
1.当解释到 def foo()时,python解释器接下来就不解释函数里的内容了即不解释print("foo").
2.当解释器解释到foo()时,就去内存里找到foo函数,执行这个函数里的内容.
3.解释器解释到foo(不加括号),就是这个函数的内存地址,foo其实就是指向了这个内存地址,和name = 'alex'是一样的.
相当于变量:
1)那么变量可以重新赋值即name = 'sb',foo是不是可以重新定义到另外一个函数的内存地址.可以
比如现在让foo = lambda a:a+1 那么此时执行foo()就是这个lambda创建的函数了.
2)name可以作为参数传入函数,那么foo是不是也可以作为参数传入函数.
4.试想如果我门定义一个函数调用并执行其他函数,是否可行:(答案是可行的)
def f1(arg): #这里的参数我们专门出入不带括号的函数名(即函数的变量名)
arg()
def func():
print("12")
f1(func)
需求演示一级处理方案:
开发有一个开放封闭原则:
大概意思就是,如果一个函数功能已经上线,想对这个功能进行扩展,不能去改功能的内部代码,只能在外进行添加.
实例:
加入现在有3个功能函数,都在线上使用,现在要对这三个功能函数调用时加上验证信息.在满足开放封闭原则的前提下如何实现?
我们就想啊想:是不是可以通过上面的(4.试想如果我们定义一个函数调用并执行其他函数时,执行我们要加入的代码)
def f1():
print('f1')
def f2():
print('f2')
def f3():
print('f3')
在定义一个能在调用这些函数时,同时进行验证
def func1(arg):
print("验证过程~~~")
arg()
这样是不是就可以实现了.但问题来了,之前调用这个函数都是f1(),f2(),f3()而现在都是func1(f1) ,func1(f2),func1(f3)
这样是不行的.我们知道f1不加括号,就是变量f1指向了函数的内存地址,那么我们将变量f1的指向改下,指向func1(f1)是不是就可以实现了,调用f1()时即调用了验证部分也调用了之前的函数 .
于是尝试
f1 = func1(f1)
结果失败:因为func1(f1)是执行func1()函数,作为参数传入的f1,也执行了.
上面f1 = func1(f1)其实是给变量f1赋的值是函数执行的结果,而不是函数.
那么我们想我们想如何将这个加了验证的函数返回,但不要执行.
我们设想,不执行这个函数,也就是函数内部的语句块不能执行,既然不能执行你就不能加在这个函数里加return,这个函数怎么返回.
所以我们要在这个函数的上层返回,也就是要在加验证的函数的外层在包一层.
于是尝试:
def auth(arg):
def inner():
print("验证过程!!!")
arg()
return inner
f1 = auth(f1)
#这里将f1作为参数传入,相当于auth函数的内存中就会有一个arg指向原先f1函数的内存指引:
f1 = "f1函数的内存地址"
arg = f1
#这里有点像变量之间赋值如:
a = 'sb'
b = a
b的指向内存地址和a的一样
a = '2b'时,
b的指向内存地址依旧是之前的'sb'
这样理解就不会怀疑当你把f1变量指引更改后,inner函数代码块中的arg()还会跟着f1变化而变化了.
总结:上面用两步解决了加验证的功能
1.将函数f1作为参数传入auth函数并执行.
2.变量f1 重新赋值为 auth(f1)的执行返回结果
那么python难道没有提供语法堂去简化上面的两步吗?答案是有:用@
@auth
def f1():
print("f1")
@auth就实现了两步,1.将f1作为参数传入auth(f1) 2.获取auth(f1)的执行结果并返回给f1(即f1 = auth(f1))
python装饰器原理二
lambda表达式是函数的简化表达方式
三元运算是if语句的简单表达方式
@auth 是装饰器的简单表达方式
python装饰器去装饰含参数的函数
上面都函数都没有参数,现在有一个带参数的函数
def auth(arg):
def inner():
print("验证过程!!!")
arg()
return inner
@auth
def f5(arg):
print("f5 is %s"%arg)
这f5是需要参数的,这个f5最终 = inner
f5有参数,所以 inner也应该有参数所以auth函数应该改成
def auth(arg):
def inner(func_arg):
print("验证过程!!!")
arg(func_arg)
return inner
@auth
def f5(arg):
print("f5 is %s"%arg)
那么紧接着问题来了,另外一个函数又有2个,3个,4个参数的函数也需要加装饰器,那么麻烦了,对于一个验证功能就要为不同参数个数就要写多个装饰器.python中难道没有办法处理啊.
有,函数我们知道有动态参数,这里就可以用,*arg和**kwargs
所以上面的装饰器就可以写成:
def auth(arg):
def inner(*arg,**kwargs):
print("验证过程!!!")
arg(*arg,**kwargs) #这里python内部语法堂,内部处理将外层函数传入进来的参数,原封不动的拿到内部函数里.没有这个语法堂,你就需要判断传入进来几个参数,然后再把参数付给变量,再在内部函数传入.你看是不是很麻烦,python语法堂就帮你做了
return inner
@auth
def f5(arg):
print("f5 is %s"%arg)
1.装饰器是一个函数,至少两层
2.执行auth函数,被装饰的函数作为参数auth(foo)
auth函数的返回值,赋值给被装饰的函数的函数名
@auth
def foo():
pass
3.动态参数,可以装饰含有n个参数的函数
4.函数的返回值
5.多装饰器
6.三层函数的装饰器如何适用.
python装饰器去装饰含返回值的函数
前面的例子讲到了前3条知识.前面的函数都没有返回值,如果函数有返回值,你应该怎么获得呢.
实例:
#假设fetch函数是获取主机列表
#对于业务线来说,是不是要获取主机列表
def auth(arg):
def inner(func_arg):
print("验证过程!!!")
arg(func_arg)
print("执行完后,做xxx操作!!!")
return inner
def fetch_server_list():
print('f6 %s'%arg)
server_list = ['c1','c2','c3']
return server_list
ret = fetch_server_list()
没有装饰器的情况下,print(ret)能够获取到列表
当加了装饰器后
@auth
def fetch_server_list():
print('f6 %s'%arg)
server_list = ['c1','c2','c3']
return server_list
ret = fetch_server_list()
print(ret)
结果是:
"验证过程!!!"
'f6 %s'%arg
"执行完后,做xxx操作!!!"
None #返回的空值,为什么是空置 .因为此时的fetch_server_list函数名实际上指引的是 inner函数的内存地址.
inner函数的语句块如下:
def inner():
print("验证过程!!!")
arg() #arg指向的是老的fetch_server_list函数的内存地址
print("执行完后,做xxx操作!!!")
此函数没有返回值.ret变量获得的是None
那么如何获得原函数的返回值呢?需要在inner函数中获得,所以装饰器应该定义成如下:
def auth(arg):
def inner(*arg,**kwargs):
print("验证过程")
result = arg(*arg,**kwargs)
print("执行过后,又做了xxxx")
return result
return inner
@auth
def fetch_server_list(arg):
print('f6 %s'%arg)
server_list = ['c1','c2','c3']
return server_list
ret = fetch_server_list("arg")
print(ret)
python 装饰器实现登录验证原理
前面我们使用装饰器完成了在调用一个函数前和后分别做了其他操作.
初衷我们是想在调用函数之前,对用户进行验证,只是我们在装饰器里只是打印"验证过程",我们现在创建一个简单的验证方法
def login():
name = 'alex'
if name == 'alex':
return True
else:
return False
def auth(func):
def inner(*args,**kwargs):
is_login = login()
if not is_login:
return "非法登录"
temp = func(*args,**kwargs)
print("after")
return temp
return inner
@auth
def fetch_server_list(arg):
print('f6 %s'%arg)
server_list = ['c1','c2','c3']
return server_list
通过这个例子看到通过使用装饰器可以做用户验证
比如你访问京东页面,在没有登录的前提下,是不能查看账户余额和订单查询.
只有登录成功后才能调用查询账户余额的页面.调用之前就对是否登录做了用户验证.
其他语言里也有类似python装饰器的功能来做验证的方式,只是其他语言不叫装饰器,叫特性.
python装饰器实现token验证
实际应用中,经常采用的验证方法是业务部门来调用后台系统时通过传过来一个key,
本地方法调用之前先去数据库取到这个用户的key来和传递过来的key进行对比.
那这个key一般都是token.
那么参数怎么传的哪.
假设业务部门调用后台模块是通过下面代码实现
basic模块是后台代码模块
import basic
key = "sfsdfadfsdfsxxvxdfew"
ret_list = basic.fetch_server_list("test",token = key)
print(ret_list)
这是业务线上的代码改完了,就是在调用fetch_server_list()函数时,相对于之前没通过装饰器加验证时多了一个参数即token = key
业务线要改动的仅此一点,那么我们要看看basic后台代码部分了.
def login():
name = 'alex'
if name == 'alex':
return True
else:
return False
def auth(func):
def inner(*args,**kwargs):
is_login = login()
if not is_login:
return "非法登录"
temp = func(*args,**kwargs)
print("after")
return temp
return inner
@auth
def fetch_server_list(arg):
print('f6 %s'%arg)
server_list = ['c1','c2','c3']
return server_list
被装饰后的函数其实就是:
def inner(*args,**kwargs):
is_login = login()
if not is_login:
return "非法登录"
temp = func(*args,**kwargs) #func是原来的fetch_server_list函数
print("after")
return temp
业务线传了两个参数进来,一个'test',一个token=key,inner函数怎么获取key呢,我们看token=key其实是型参**kwargs,所以获取key就需要kwargs['key']
所以装饰器应该写成:
def auth(func):
def inner(*args,**kwargs):
key = kwargs["token"]
is_login = login(*args,key) #python语法堂中 外层函数通过型参*args和**kwargs获得实参,如果内层函数也是通过型参*args和**kwargs获得实参,那么外层函数传进来什么样子,内层函数获得的就是什么样子.前面带装饰带参数的函数中提到过.
if not is_login:
return "非法登录"
temp = func(*args,**kwargs) #python语法堂中 同上....
print("after")
return temp
return inner
由于上面开始使用key来做验证了,所以login函数应该换了
def login(name,key):
local_key = "通过name从数据库里查出来,并且赋值给local_key"
if local_key == key:
return True
else:
return False
#装饰器改到这个程度,应该可以满足我们传入验证参数的需求了,但实际上还有些错误.我们仔细看inner函数中
def inner(*args,**kwargs):
key = kwargs["token"]
is_login = login(*args,key)
if not is_login:
return "非法登录"
temp = func(*args,**kwargs) #func是原来的fetch_server_list函数
print("after")
return temp
#func是原来的fetch_server_list函数,那么问题来了,原来的fetch_server_list函数只能接收一个参数,
这里由于python语法堂对型参*args,**kwargs的特性,这个老函数同样会获得到两个参数,
那么上面业务线上调用时传入的参数就会报错:
ret_list = basic.fetch_server_list("test",token = key)
要怎样解决呢
只需要在inner函数中获得key后,把token=key参数删除即可.这里就可以想到字典的pop()方法了.所以上面的装饰器要改成:
def auth(func):
def inner(*args,**kwargs):
key = kwargs.pop("token")
is_login = login(*args,key)
if not is_login:
return "非法登录"
temp = func(*args,**kwargs) #这里**kwargs在获得key时从inner函数内存块中删掉了,所以字典就为空.根据语法堂对**kwargs型参的特性,这里就为空了,而不是传入一个空字典了.
print("after")
return temp
return inner
到此,使用token进行验证就完结了,正确代码如下:
def login(name,key):
local_key = "通过name从数据库里查出来,并且赋值给local_key"
if local_key == key:
return True
else:
return False
def auth(func):
def inner(*args,**kwargs):
key = kwargs.pop("token") #获得传入的key值后,将键值对删除.
is_login = login(*args,key)
if not is_login:
return "非法登录"
temp = func(*args,**kwargs) #这里**kwargs在获得key时从inner函数内存块中删掉了,所以字典就为空.根据语法堂对**kwargs型参的特性,这里就为空了,而不是传入一个空字典了.
print("after")
return temp
return inner
@auth
def fetch_server_list(arg):
print('f6 %s'%arg)
server_list = ['c1','c2','c3']
return server_list
python 装饰器之多层装饰器
多个装饰器装饰一个函数的场景是
很多函数,这些函数有的只需要通过用户验证,有得不仅需要用户验证,还需要进行权限验证
简单
def w1(func):
def inner():
print("w1 before")
func()
print("w1 after")
return inner
def w2(func):
def inner():
print("w2 before")
func()
print("w2 after")
return inner
@w2
@w1
def foo():
print("foo")
foo()
执行结果
w2 before
w1 before
foo
w1 after
w2 after
相当于盒子套盒子.
了解此方法和知道运行顺序即可.
python装饰器之装饰器加参数一:
python装饰器之装饰器加参数二:
这两节加一起讲了三层函数的装饰器,三层函数的装饰器其实就是把要加入的动能函数作为参数传入到装饰器调用时
@auth(before函数,after函数)
def foo():
print("foo")
为什么是三层,而不是在两层里把before和after传入进去呢.
如:
def before():
print("before")
def after():
print("after")
def auth(func,arg_before,arg_after):
def inner():
arg_before()
func()
arg_after()
return inner
def foo():
print("foo")
这里如果不用@,使用两层函数是可以的,但要实现装饰器的效果,就需要两步
1.将参数传入
auth(foo,before,after)
2.将返回的结果赋值给被装饰函数的函数名
foo = auth(foo,before,after)
也就是你有多少函数要写多少次
foo = auth(foo,before,after)
这样也不是不行,但是你没有使用python内部提供的语法堂@符号.显得不高级.
但使用时,又有一个问题
@auth 这里的语法,只将下面要装饰的函数作为参数传入auth函数.不能将before和after作为参数传入,那你会说,难道不能写成
@auth(before,after)吗?答案是不能,因为这样auth(before,after)只有两个参数,语法就是语法你不能改变他.那么我们就要想,我们在加一层,在上面一层传入参数
于是就变成
def before():
print("before")
def after():
print("after")
def Filter(a1,a2):
def outer(func):
def wrapper():
a1()
temp = func()
a2()
return temp
return wrapper
return outer
这样
@Filter(a1,a2)时相当于,把a1\a2传入到了Filter函数,
大家看Filter函数返回的是不是outer函数,其实返回的就是之前的二层函数的外层.并且不是加括号的,
这样是不是就满足了@auth这样的格式了.ok,这就是为什么要用3层函数来传入之前之后的代码的原因.
11 python s12 day4 递归原理及实现
12 python s12 day4 通过递归实现斐波那契数列
上面两节关于递归的视频,用11期银角大王视频代替
python递归原理
需求:打印
0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765.....
我们看到上面的一组数是有规律的:从第三个数开始,每个数都是等于前两个数的和.
那我们就想通过函数实现,写一个函数,传入两个数字作为最开始的两个数字,后面的第三个数字就等于他们的和
def func(arg1,arg2):
if arg1 == 0:
print(0)
if arg2 == 1:
print(1)
arg3=arg1+arg2
print(arg3)
func(arg2,arg3)
这样就可以实现,把arg3算出来的结果在函数内部在作为参数传入函数.这样就一直循环下去,如果想停我们可以设置一个值来做if判断
递归常用的应用场景计算器:
假设用户传入了一个含有多个括号的运算表达式如:
str = '98+234*(234-23)/88+((3+2)/4+44/4)*3-33*-4'
我们就可以写一个递归函数,
1.用正则表达式查找第一个不含"("")"的字符串str1,取出后计算得到结果re1,把结果替换到大字符串中
str = str.replace(str1,re1)
然后在把上面获得到的str作为参数在函数内部再次传入这个函数,这样循环到最后,直到计算出结果.返回即可.这是思路,具体实现见作业把.
python 递归返回值:
上面打印的需求,现在要加一条返回第一个大于1000的值,所以我们在更改函数为:
def func(arg1,arg2):
if arg1 == 0:
print(0)
if arg2 == 1:
print(1)
arg3=arg1+arg2
#print(arg3)
if arg3 > 1000:
return arg3
func(arg2,arg3)
ret = func(0,1)
print(ret)
执行结果为
None
问题来了,为什么没有返回1597,而是返回None
原因是,假设是在第十次函数执行时返回1579,那么第十次返回,返回给谁了呢,返回给第九次,因为是第九次执行的.
那第九次的有没有返回给第八次,显然是没有的,因为代码中除了满足arg3>1000时才返回,而第九次不满足所以没有返回给他的调用者(第八次)
同样第八次也没有返回给第七次,第七次没有返回给第六次 ......一直到第一次执行没有返回结果,所以最终未能返回想要的值给用户.
那么如何实现呢?只要给函数内部调用函数时,返回即可.代码更改成:
def func(arg1,arg2):
if arg1 == 0:
print(0)
if arg2 == 1:
print(1)
arg3=arg1+arg2
#print(arg3)
if arg3 > 1000:
return arg3
return func(arg2,arg3) #前面加一个return即可
ret = func(0,1)
print(ret)
执行结果为
1579
13 python s12 day4 算法基础之二分查找
一个需求:判断一个数字是否在一个列表中
data = list(range(1,600,3))
判断299在不在data列表中.
我们第一印象是用in 方法来判断.那么我们在考虑,in语法的内部是怎么实现的.
in是通过遍历data这个列表,然后一个一个对比,然后 li == 299 为真,
那么问题来了,如果是在6百万或者更大的数据中判断一个值,是不是要循环600W次,那岂不是花很久才能得到结果.有没有好的办法来判断呢,答案是有,用二分算法.
思路:
能不能缩小范围,这个列表是有序的,我们找到这个列表的中间的那个值.如果中间值比我们的值大,我们去找中间左边的范围,如果比我们的值小,那么找右边的.
紧接着利比较中键值的方法去剩下的范围去找.
实现:
用到递归函数的知识.
def binary_search(data_source,find_n):
if len(data_source)>1:
mid = int(len(data_source)/2) #找到中间的下标
tmp_n = data_source[mid] 把那个中间值取到
if tmp_n == find_n:
print("%s找到了~~~值在列表中的位置%s!"%(find_n,mid))
elif tmp_n > find_n: #表示要找的值在左边
binary_search(data_source[:mid],find_n)
elif data_n < find_n: #表示要找的值在右边
binary_search(data_source[mid:])
elif data_source[0] == find_n:
print("找到了")
else:
pirnt("不在这个列表中")
真实生产用途:
判断访问网站的来源地址属于哪的.
有一个IP地址库,地址库根据省市换段,先将ip地址换算成长整数(有专门的模块)
然后拿这个长整数去地址库的长整数段去比较,ip地址库大概4000W条数据,用二分法2秒钟找到.
14 python s12 day4 算法基础之2维数组90度旋转
要求:生成一个4*4的2维数组并将其顺时针旋转
[i for i in range(10)] 这个语法之前没用过.
相当于生成一个新列的空列表,然后在循环for i in range(10)将i 加入到列表,结果是
>>> a = [i for i in range(10)]
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [col for col in range(4) for row in range(4)]
[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
>>> [[col for col in range(4)] for row in range(4)]
[[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
>>> data = [[col for col in range(4)] for row in range(4)]
>>> for i in data:print(i)
...
[0, 1, 2, 3]
[0, 1, 2, 3]
[0, 1, 2, 3]
[0, 1, 2, 3]
目的变成
[0,0,0,0]
[1,1,1,1]
[2,2,2,2]
[3,3,3,3]
怎么做?
思路分析:
把第一列的每一个值变成第一行,把第二列的每一个值变成第二行
把第三列的每一个值变成第三行,把第四列的每一个值变成第四行
我们只拿下标进行循环,这样才能去更换正在被循环的列表.
就是拿data[0][1] 和data[1][0]调换
拿data[0][2] 和data[2][0]调换
拿data[0][3] 和data[3][0]调换
for r_index in range(len(data)):
for c_index in range(len(data[r_index])):
#data[c_index][r_index] #这里就是小循环的下标值找大循环的行比如 [0][1] 这里0是大循环的下标,1为小循环的下标.前面分析data[0][1]要和data[1][0]
tmp = data[c_index][r_index]
data[c_index][r_index] = data[r_index][c_index]
data[r_index][c_index] = tmp
#上面三步完成了替换.一直替换到大循环第一个元素的元素循环完毕.
#当大循环循环到第二个元素,按照我们上面的思路,就变成[1][0] 和 [0][1]值对换,[1][2]和[2][1]对换.
前面的[1][0]和[0][1] 就不需要循环了.那怎么才能排除第一次换的呢.
在小循环中把循环的开始变为大循环的r_index,这样就可以了.
for r_index in range(len(data)):
for c_index in range(len(r_index,data[r_index])):
#data[c_index][r_index] #这里就是小循环的下标值找大循环的行比如 [0][1] 这里0是大循环的下标,1为小循环的下标.前面分析data[0][1]要和data[1][0]
tmp = data[c_index][r_index]
data[c_index][r_index] = data[r_index][c_index]
data[r_index][c_index] = tmp
15 python s12 day4 正则表达式基础及计算器作业思路及要求
正则表达式:
import re #正则表达式模块
1.match()函数
2.search()函数
result1 = re.match('\d+', '321sdf 23sdfsf 4sdf2345’) #第一个参数你要找的正则表达式,第二个参数从这个字符串中找
print result1
result2 = re.search('\d+','321sdf 23sdfsf 4sdf2345’) #第一个参数你要找的正则表达式,第二个参数从这个字符串中找。
print result2
执行结果
<_sre.SRE_Match object at 0x1101d63d8>
<_sre.SRE_Match object at 0x1101d6440>
可以看出得到的都是对象,既然是对象就有方法。肯定就有一种方法,得到返回的值,那就是group()方法。
import re
result1 = re.match('\d+', '321sdf 23sdfsf 4sdf2345’)
print result1
print result1.group()
result2 = re.search('\d+','321sdf 23sdfsf 4sdf2345’)
print result2
print result2.group()
执行结果
<_sre.SRE_Match object at 0x108158370>
321
<_sre.SRE_Match object at 0x1081583d8>
321
那么结果是一样的,看不出match和search的区别。先说明下,这两个方法的区别是,match从起始位开始搜索,当搜索到了则返回对象,通过方法可以获得值,当启始位没搜到,返回None,即不是类,不具有方法。而seach方法是从全文搜索,全文都没有找到,则也返回None,将上面的代码更改如下
import re
result1 = re.match('\d+', ‘a321sdf 23sdfsf 4sdf2345’) #多加了a
print result1
print result1.group()
result2 = re.search('\d+','321sdf 23sdfsf 4sdf2345’)
print result2
print result2.group()
执行结果如下
Traceback (most recent call last):
File "/Users/tedzhou/workspace/s8day3/main/index.py", line 213, in <module>
None #这里得到了一个值,接下来就是语法错误,也就是None不是对象,不具有方法
print result1.group()
AttributeError: 'NoneType' object has no attribute ‘group'
将代码加入if判断如下
import re
result1 = re.match('\d+', ‘a321sdf 23sdfsf 4sdf2345’) #多加了a
if result1:
print result1.group()
else:
print ’nothing'
result2 = re.search('\d+’,'a321sdf 23sdfsf 4sdf2345’)
print result2
print result2.group()
执行结果
nothing
<_sre.SRE_Match object at 0x106592370>
321
3.findall()函数
import re
result3 = re.findall('\d+', 'sdf12311sfd888ddfff999ll')
print result3
执行结果
['12311', '888', '999’]
找到的都拿过来。
4.compile()函数
我们在执行调用.py文件时会生成.pyc文件,这个.pyc文件可以理解为编译后的文件,目的为了加速。
那么python为了在查找某个正则表达式快的时候,就提供一个方法将这个字符串编译的方法,就是compile()
使用举例:
import re
com = re.compile('\d+’)
编译后,com就是一个对象,具体啥对象print type(com)查看没有结果,老师说是c编译的,python下找不到,不管了,是对象就有方法,它有findall()方法。
print type(com)
print com.findall(‘dd2222cc3333gg88ss’)
执行结果
<type '_sre.SRE_Pattern’> #老师也不知道是啥对象
['2222', '3333', '88']
com除了findall,还有match()和search()
5.还有一个groups()方法
得到的是组
import re
result5 = re.search('(\d+)cc(\d+)','dd2222cc3333gg88ss')
print result5
print result5.groups()
执行结果是
('2222', '3333’)
这里看我们得到的是2222cc3333中的’2222’,’3333’
那为什么没得到’cc’呢
因为查询参数中,是吧(\d+)作为组,而cc没有作为一个小组。
结论:groups()方法是得到查询结果中的组。
6.比较特殊且常用的匹配实例:
1.匹配整数或者浮点数
>>> s = '2.03-4.0'
>>> b = re.search('[\d\.\d]+',s)
>>> b.group()
'2.03'
>>> s = '3+2.03-4.0'
>>> b = re.search('[\d\.\d]+',s)
>>> b.group()
'3'
>>>