python 学习第四天

1.迭代器&生成器

2.装饰器

   1.基本装饰器

   2.多参数装饰器(了解)

3.递归

4.算法基础:二分查找,二维数组转换,冒泡排序

5.正则表达式

迭代器&生成器

迭代器

迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,知道所有的元素都被访问结束。 迭代器只能往前不会后退, 另外,迭代器的一个大优点是不要求实现准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素。这个特性使 迭代器特别适用于便利一些巨大的或是无限的结合, 比如说几个G的日志文件。

特点:

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

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

3.访问时不能回退

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

生成一个迭代器如下:

>>> a = iter([1,2,3,4,5,6,7,8])
>>> a.__next__
<method-wrapper '__next__' of list_iterator object at 0x02ED0CF0>
>>> a.__next__()
1
>>> a.__next__()
2
>>> a.__next__()
3
>>> a.__next__()
4
>>> a.__next__()
5
>>> 
View Code

注:迭代器不能随意访问集合中的某一个值,只能从头到尾依次访问,且访问时不能回退

生成器generator:

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

代码如下:

def test_cash(abc):
    while abc>=0:
        abc -= 100
        yield 100
        print('又来取钱了')

abc = test_cash(500)

print(abc.__next__())
print(abc.__next__())
print(abc.__next__())
print('中断一会,休息一下')
print(abc.__next__())
View Code

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

另外, 还可以通过yield实现在单线程的情况下实现并发运算的效果(实现异步):

代码如下:

import time
def consumer(name):
    print('%s 要吃包子了'%name)
    while True:
        baozi = yield
        print('%s 包子来了,包子要被%s 吃掉了'%(baozi,name))
def producer(name):
    C = consumer('A')
    C1 = consumer('B')
    C.__next__()
    C1.__next__()
    print('我要开始做包子啦')
    for i in range(10):
        time.sleep(1)
        print('%s 做了两个包子'%name)
        C.send(i)
        C1.send(i)
producer('test')

装饰器:

python装饰器见另一片文档。

递归

特点

递归算法是一种直接或者间接地调用自身方法的过程,它往往使算法的描述简介而且易于理解。

递归算法解决问题的特点::

(1) 递归就是在过程或函数里调用自身。

(2)在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口

(3)递归算法截图通常显得很间接,但递归算法结题的运行效率极低,所以一般都不提倡用递归算法设计程序。

   在递归调用的过程当中系统为每一层的返回点、局部变量等开辟了栈来存储。递归次数过程容易造成栈溢出等, 所以一般都提倡用递归算法设计程序。

要求

递归算法所体现的“重复” 一般有三个要求:

一是每次调用都在规模上都有所缩小(通常都是减半)

二是相邻两次重复之间有紧密的联系, 前一次要为后一次做准备(通常前一次的输出是为后一次的输入做铺垫)

三是在问题的规模极小时而不再进行递归调用,因而每次递归调用都是有条件的, 无条件出口的递归调用最后会陷入死循环。

示例代码如下:

在数据量比较大的情况下通过二分法查找某个数据

def searchdate(data_result,find_n):
    mid = int(len(data_result)/2)
    if len(data_result) >1:
        if find_n < data_result[mid]:
            print('find_n in [mid] left')
            searchdate(data_result[:mid],find_n)
        elif find_n > data_result[mid]:
            print('find_n in [mid] right')
            searchdate(data_result[mid:],find_n)
        else:
            print('find date in data_result [%s]' %data_result[mid])
if __name__ == '__main__':
    dabc = list(range(1,99999))
    searchdate(dabc,57668)

通过二分算法我们可以很快的实现数据查找, 特别是在数据量比较大的情况下, 效果会更好。

算法基础

1.生成一个4*4的二维数组并将其瞬时旋转90度

# 生成一个二维数组
date = [[aaa for aaa in range(4)] for bbb in range(4)]
name = '打印'
result = name.center(30, '*')
for i in date:
print(i)
for r_index, row in enumerate(date): # 循环遍历数组,并获取第一层的数组下标
for c_index in range(r_index, len(row)): # 根据第一层的下标,获取第二层
tmp = date[c_index][r_index] # 将要交换的元素先存到临时变量中
date[c_index][r_index] = row[c_index] # 元素交换
date[r_index][c_index] = tmp
print(result)

for r in date:
print(r)
##################另外一种写法##################
data = [[aaa for aaa in range(4)] for bbb in range(4)]
for i in range(data.__len__()):
for k in range(data.__len__()):
if (i>k):
temp = data[i][k]
data[i][k]= data[k][i]
data[k][i]=temp

for i in data:
print(i)

ps:对于第一种写法目前还是不太能理解,后期需要在看一遍视频,加深一下

2. 斐波那契数列算法:

简单的来说斐波那契数列就是第三个数值等于第一个数值+第二个数值之和,如下:

1 2 3 5 8 13 21 34 ....

示例代码如下:

def calr(arg1,arg2,stop):
    if arg1 == 0:
        print(arg1,arg2)
    arg3 = arg1 + arg2
    print(arg3)
    if arg3 <stop:
        calr(arg2,arg3,stop)

calr(0,1,789)

3.冒泡排序

将一个不规则的数组按从小到大的顺序进行排序

代码如下:

data = [10,4,33,21,54,3,8,11,5,22,2,1,17,13,6]
 
print("before sort:",data)
 
previous = data[0]
for j in range(len(data)):
    tmp = 0
    for i in range(len(data)-1):
        if data[i] > data[i+1]:
            tmp=data[i]
            data[i] = data[i+1]
            data[i+1] = tmp
    print(data)
 
print("after sort:",data)


################另外一种写法###################
data = [11, 1231, 124, 24123, 554, 632, 591, 112, 109, 889, 100]
print('before sort:', data)
for i in range(len(data)):
for k in range(i):
if data[i] < data[k + 1]:
data[i], data[k + 1] = data[k + 1], data[i]
print('after sort:', data)

正则表达式 

语法:

import re
'''生成要匹配的正则对象,^代表从头开始[0-9]代表匹配0至9的任意一个数字,
# 所以这里的意思是对传进来的字符串进行匹配,如果这个字符串的开头第一个字符是数字,就代表匹配上了'''
p = re.compile("^[0-9]")
'''按上面生成的正则对象 去匹配 字符串, 如果能匹配成功,这个m就会有值, 否则m为None<br><br>if m: #不为空代表匹配上了'''
m = p.match('14534Abc')
print(m.group())
也可以合并到一行来写:
= p.match("^[0-9]",'14534Abc')
效果是一样, 去别是一个第一种方式需要先对正则进行编译,然后再去做匹配,第二种写法是每次执行的时候,都需要进行便宜
如果数据量较大的情况下,建议使用第一种写法, 这样会提高性能。

匹配格式

模式描述
^ 匹配字符串的开头
$ 匹配字符串的末尾。
. 匹配任意字符,除了换行符,当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 匹配任意空白字符,等价于 [ f].
S 匹配任意非空字符
d 匹配任意数字,等价于 [0-9].
D 匹配任意非数字
A 匹配字符串开始
 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。c
z 匹配字符串结束
G 匹配最后匹配完成的位置。
 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
B 匹配非单词边界。'erB' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
, , 等. 匹配一个换行符。匹配一个制表符。等
1...9 匹配第n个分组的子表达式。
10 匹配第n个分组的子表达式,如果它经匹配。否则指的是八进制字符码的表达式。

正则表达式常用5种操作

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

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

import re
p = re.compile("[0-9]")
m = p.search("asdja21skdjl")
print(m.group())

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

代码如下:

import re
p = re.compile("[0-9]")
m = p.split("testL1testM2testC")
print(m)

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

import re
p = re.compile("[0-9]")
m = p.findall("asdja21skdjlasdlajd1lajd 2 sadkljsal3 jalksjd2")
print(m)
输出如下:['2', '1', '1', '2', '3', '2']

re.sub(self, repl, string, count=0)    # 替换匹配到的字符

import re
p = re.compile("[0-9]")
m = p.sub("&","asdja21skdjlasdlajd1lajd 2 sadkljsal3 jalksjd2",count=5)
print(m)

正则表达式实例

字符匹配

实例描述
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] 匹配除了数字外的字符

特殊字符类

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

原文地址:https://www.cnblogs.com/apnsa/p/5158101.html