Python学习第四天

迭代器:

迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完才结束。迭代器只能向前不会后退,不过这没什么大不了的,因为人们很少在迭代中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中的所有元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件。

特点:

1、  访问者不需要关心迭代器内部的结构,仅需要通过next()方法不断去取下一个内容。

2、  不能随机访问集合中的某个值,只能从头到尾依次访问。

3、  访问到一半时不能往回退。

4、  便于循环比较大的数据集合,节省内存。

1 names=iter(['alex','jack','rain'])
2 print(names)
3 print(names.__next__())
4 print(names.__next__())
5 
6 <list_iterator object at 0x006ED2B0>
7 alex
8 jack

生成器的使用:

定义:一个函数调用的时候返回一个迭代器,那这个函数就叫做生成器,如果函数中包含yield语法,那这个函数就会变成生成器。

 1 def cash_out(amount):
 2    while amount>0:
 3        amount-=100
 4        yield 100
 5 print('又来取钱呢啦!')
 6 atm=cash_out(500)
 7 print(type(atm))
 8 print(atm.__next__())
 9 print(atm.__next__())
10 print('叫个大保健…')
11 print(atm.__next__())
12 
13 又来取钱呢啦!
14 <class 'generator'>
15 100
16 100
17 叫个大保健…
18 100

作用:

这个yield的主要效果呢,就是可以使函数中断,并保存中断状态,中断后,代码可以继续往下执行,过一段时间还可以再重新调用这个函数,从上次yield的下一句开始执行。

另外,还可通过yield实现在单线程的情况下实现并发运算的效果(这就是我们所熟知的生产者-消费者模型)

生产者-消费者模型:

 1 import time
 2 def consumer(name):
 3     print("%s 准备吃包子啦!" %name)
 4     while True:
 5        baozi = yield
 6 
 7        print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
 8 
 9 def producer(name):
10     c = consumer('A')
11     c2 = consumer('B')
12     c.__next__()
13     c2.__next__()
14     print("老子开始准备做包子啦!")
15     for i in range(10):
16         time.sleep(1)
17         print("做了2个包子!")
18         c.send(i)
19         c2.send(i)
20 
21 producer("alex")
View Code

装饰器原理介绍和基本实现:

 原理:

 1 def  login(func):
 2      print('passed user verification…')
 3      return func
 4 def home(name):
 5    print('welcome [%s] to home page'%name)
 6 def tv(name):
 7    print('welcome [%s] to tv page'%name)
 8 def moive(name):
 9    print('welcome [%s] to moive page'%name)
10 tv=login(tv)
11 tv(name='peony')
12 
13 passed user verification…
14 welcome [peony] to tv page

基本实现:

 1 def  login(func):
 2      def inner(arg):
 3         print('passed user verification…')
 4         func(arg)
 5      return inner
 6 def home(name):
 7    print('welcome [%s] to home page'%name)
 8 @login
 9 def tv(name):
10    print('welcome [%s] to tv page'%name)
11 def moive(name):
12    print('welcome [%s] to moive page'%name)
13 tv('Alex')
14 
15 passed user verification…
16 welcome [Alex] to tv page

实现带参数的复杂装饰器:

 1 def w1(func):
 2     def inner(arg):
 3         # 验证1
 4         # 验证2
 5         # 验证3
 6         return func(arg)
 7     return inner
 8 
 9 @w1
10 def f1(arg):
11     print 'f1'
12 
13 一个参数
一个参数
 1 def w1(func):
 2     def inner(arg1,arg2):
 3         # 验证1
 4         # 验证2
 5         # 验证3
 6         return func(arg1,arg2)
 7     return inner
 8 
 9 @w1
10 def f1(arg1,arg2):
11     print 'f1'
12 
13 两个参数
两个参数
 1 def w1(func):
 2     def inner(arg1,arg2,arg3):
 3         # 验证1
 4         # 验证2
 5         # 验证3
 6         return func(arg1,arg2,arg3)
 7     return inner
 8 
 9 @w1
10 def f1(arg1,arg2,arg3):
11     print 'f1'
12 
13 三个参数
三个参数

可以装饰具有处理n个参数的函数的装饰器:

 1 def w1(func):
 2     def inner(*args,**kwargs):
 3         # 验证1
 4         # 验证2
 5         # 验证3
 6         return func(*args,**kwargs)
 7     return inner
 8  
 9 @w1
10 def f1(arg1,arg2,arg3):
11     print 'f1'
装饰的函数具有n个参数

一个函数可以被多个装饰器装饰:

 1 def w1(func):
 2     def inner(*args,**kwargs):
 3         # 验证1
 4         # 验证2
 5         # 验证3
 6         return func(*args,**kwargs)
 7     return inner
 8  
 9 def w2(func):
10     def inner(*args,**kwargs):
11         # 验证1
12         # 验证2
13         # 验证3
14         return func(*args,**kwargs)
15     return inner
16  
17  
18 @w1
19 @w2
20 def f1(arg1,arg2,arg3):
21     print 'f1'
一个函数被多个装饰器装饰

(1)简单的装饰器:

1 def w1(main_func):
2     def outer(request,kargs):
3      print('before')
4      main_func(request,kargs)
5      print('after')
6     return outer
7 @w1
8 def show():
9     print('show')

其执行流程为:

python解释器就会从上到下解释代码,步骤如下:

  1. def w1(main_func):  ==>将w1函数加载到内存
  2. @w1

没错,从表面上看解释器仅仅会解释这两句代码,因为函数在没有被调用之前其内部代码不会被执行。从表面上看解释器着实会执行这两句,但是 @w1 这一句代码里却有大文章,@函数名 是python的一种语法糖。如上例@w1内部会执行以下操作:

    • 执行w1函数,并将 @w1 下面的 函数 作为w1函数的参数,即:@w1 等价于 w1(show),show函数重新定义为w1(show)的返回值

    • 执行show(),这个时候是新show()=outer,即为
print('before')
main_func(request,kargs)#原来的show()
print('after')

(2)复杂的装饰器:

 1 def Before(request,kargs):
 2     print('before')
 3 def After(request,kargs):
 4     print('after')
 5 def Filter(before_func,after_func):
 6     def outer(main_func):
 7         def wrapper(request,kargs):
 8              before_func(request,kargs)
 9              main_func(request,kargs)
10              after_func(request,kargs)
11         return wrapper
12     return outer
13 
14 @Filter(Before, After)
15 def Index(request,kargs):
16     print ('index')

其执行流程为:

(1)执行Filter(before,after)

(2)@Filter(before,after)变成@outer,其参数是Index

(3)新Index=wrapper()

递归原理及实现:

递归

特点

递归算法是一种直接或者间接地调用自身算法的过程。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。
递归算法解决问题的特点:
(1) 递归就是在过程或函数里调用自身。
(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
(3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。
(4) 在 递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成 栈溢出等。所以一般不提倡用递归算法设计程序。

要求

递归算法所体现的“重复”一般有三个要求:
一是每次调用在规模上都有所缩小(通常是减半);
二是相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);
三是在问题的规模极小时必须用直接给出解答而不再进行 递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。
举一个简单的小例子:
 1 def calc(n):
 2     print(n)
 3     if n/2>1:
 4         res=calc(n/2)
 5         print('res:',res)
 6         print("N:",n)
 7         return n
 8 calc(10)
 9 
10 10
11 5.0
12 2.5
13 1.25
14 res: None
15 N: 2.5
16 res: 2.5
17 N: 5.0
18 res: 5.0
19 N: 10

(1)使用递归实现二分查找算法,

 1 def binary_search(data_source,find_n):
 2     mid=int(len(data_source)/2)
 3     if len(data_source)>=1:
 4         if data_source[mid]>find_n:
 5             print("data in left of [%s]"%data_source[mid])
 6             binary_search(data_source[:mid],find_n)
 7         elif data_source[mid]<find_n:
 8             print("data in right of [%s]"%data_source[mid])
 9             binary_search(data_source[mid:],find_n)
10         else:
11             print("found find_s,",data_source[mid])
12     else:
13         print("cannot find...")
14 if __name__=='__main__':
15     data=list(range(1,6000000))
16     binary_search(data,65535)

(2)使用递归实现斐波那契数列,

1 def func(arg1,arg2,stop):
2        if arg1==0:
3           print (arg1,arg2)
4        arg3=arg1+arg2
5        print(arg3)
6        if arg3<stop:
7            func(arg2,arg3,stop)
8 func(0,1,30)

(3)算法基础之2维数组90度旋转:

data=[[col for col in range(4)] for row in range(4)]
for row in data:
    print(row)
print('-------------')
for r_index,row in enumerate(data):
    for c_index in range(r_index,len(row)):
        tmp=data[c_index][r_index]
        data[c_index][r_index]=row[c_index]
        data[r_index][c_index]=tmp
    print('-------------')
    for r in data:print(r)

正则表达式基础:

语法:

1 import re #导入模块名
2  
3 p = re.compile("^[0-9]")  #生成要匹配的正则对象 , ^代表从开头匹配,[0-9]代表匹配0至9的任意一个数字, 所以这里的意思是对传进来的字符串进行匹配,如果这个字符串的开头第一个字符是数字,就代表匹配上了
4  
5 m = p.match('14534Abc')   #按上面生成的正则对象 去匹配 字符串, 如果能匹配成功,这个m就会有值, 否则m为None<br><br>if m: #不为空代表匹配上了
6   print(m.group())    #m.group()返回匹配上的结果,此处为1,因为匹配上的是1这个字符<br>else:<br>  print("doesn't match.")<br>

上面的第2 和第3行也可以合并成一行来写:

m = p.match("^[0-9]",'14534Abc')

它们的效果是一样的,区别在于:第一种方式是提前对要匹配的格式进行了编译(对匹配公式进行解析),这样再去匹配的时候就不用在编译匹配的格式,第2种简写是每次匹配的时候 都 要进行一次匹配公式的编译,所以,如果你需要从一个5w行的文件中匹配出所有以数字开头的行,建议先把正则公式进行编译再匹配,这样速度会快点。

匹配格式

模式描述
^匹配字符串的开头
$匹配字符串的末尾。
.匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。
[...]用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k'
[^...]不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
re*匹配0个或多个的表达式。
re+匹配1个或多个的表达式。
re?匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
re{ n} 
re{ n,}精确匹配n个前面表达式。
re{ n, m}匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式
a| b匹配a或b
(re)G匹配括号内的表达式,也表示一个组
(?imx)正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。
(?-imx)正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。
(?: re)类似 (...), 但是不表示一个组
(?imx: re)在括号中使用i, m, 或 x 可选标志
(?-imx: re)在括号中不使用i, m, 或 x 可选标志
(?#...)注释.
(?= re)前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。
(?! re)前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功
(?> re)匹配的独立模式,省去回溯。
\w匹配字母数字
\W匹配非字母数字
\s匹配任意空白字符,等价于 [\t\n\r\f].
\S匹配任意非空字符
\d匹配任意数字,等价于 [0-9].
\D匹配任意非数字
\A匹配字符串开始
\Z匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。c
\z匹配字符串结束
\G匹配最后匹配完成的位置。
\b匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\n, \t, 等.匹配一个换行符。匹配一个制表符。等
\1...\9匹配第n个分组的子表达式。
\10匹配第n个分组的子表达式,如果它经匹配。否则指的是八进制字符码的表达式。

正则表达式常用5种操作:

re.match(pattern, string)     # 从头匹配

re.search(pattern, string)    # 匹配整个字符串,直到找到一个匹配

re.split()            # 将匹配到的格式当做分割点对字符串分割成列表

1 import re
2 m = re.split("[0-9]", "alex1rain2jack3helen rachel8")
3 print(m)
4 输出:
5 ['alex', 'rain', 'jack', 'helen rachel', '']

re.findall()          # 找到所有要匹配的字符并返回列表格式

1 import re
2 m = re.findall("[0-9]", "alex1rain2jack3helen rachel8")
3 print(m)
4 输出:
5 ['1', '2', '3', '8']

re.sub(pattern, repl, string, count,flag)    # 替换匹配到的字符

1 import re
2 m=re.sub("[0-9]","|", "alex1rain2jack3helen rachel8",count=2 )
3 print(m)
4 输出:
5 alex|rain|jack3helen rachel8
正则表达式实例

字符匹配

实例描述
python匹配 "python".
字符类
实例描述
[Pp]ython匹配 "Python" 或 "python"
rub[ye]匹配 "ruby" 或 "rube"
[aeiou]匹配中括号内的任意一个字母
[0-9]匹配任何数字。类似于 [0123456789]
[a-z]匹配任何小写字母
[A-Z]匹配任何大写字母
[a-zA-Z0-9]匹配任何字母及数字
[^aeiou]除了aeiou字母以外的所有字符
[^0-9]

匹配除了数字外的字符

特殊字符类
实例描述
.匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。
\d匹配一个数字字符。等价于 [0-9]。
\D匹配一个非数字字符。等价于 [^0-9]。
\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\w匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
\W匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。

re.match与re.search的区别

re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。

转载于:https://www.cnblogs.com/Peony-Y/p/5194921.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值