坚持就是胜利。今天零下14度,从教室出来的路上真的很冷很冷,希望这个冬天自己不会白过,春暖花开的时候一定要给世界一个更好的自己。
原本以为day3的作业自己做得挺好的,没想到只得了B+。必须要加油了,比自己牛逼的人那么多,没有理由不再努力一些。
==>the start
1.迭代器(iterator)&生成器(generator)
迭代器可以被next()函数调用并返回下一个值,节省内存空间。注:Python3.0中使用__next__()
tmp = iter(['alex', 'jack', 'rain']) print(tmp.__next__()) print(tmp.__next__()) print(tmp.__next__()) print(tmp.__next__()) # 再取值就会报错 list_tmp = [1, 22, 333, 4444, 55555] for i in iter(list_tmp): print(i)
能被for直接循环的都是可迭代对象,如列表,字典等。判断一个对象是不是可迭代对象,可以使用isinstance(*, Iterable)来判断。
生成器在被调用的时候返回一个迭代器。生成器有个标志性的语法yield。
当生成器被调用时,yield返回一个值,并记住当前位置,下一次调用时,从yield下一句语句运行返回下一个值。
def catch_mony(amount): while amount > 0: amount -= 100 print("又来取钱了!") yield "给你100吧,剩余:{}".format(amount) atm = catch_mony(500) print(type(atm)) print(atm.__next__()) print(atm.__next__()) print("去看电影!。。。") print(atm.__next__()) ====================================== 运行结果: <class 'generator'> 又来取钱了! 给你100吧,剩余:400 又来取钱了! 给你100吧,剩余:300 去看电影!。。。 又来取钱了! 给你100吧,剩余:200
此外,yield还有实现在单线程模式下实现并发运算的效果。如下例:
import time def consumer(name): print("{}准备吃包子啦!".format(name)) while True: baozi = yield # yield也可以用于接收值 print("第{}次的包子来了,被{}吃掉了!".format(baozi, name)) def producer(name): c1 = consumer('A') c2 = consumer('B') c1.__next__() c2.__next__() print("{}准备开始做包子了!".format(name)) for i in range(1, 11): time.sleep(1) print("{}第{}次做了两个包子。".format(name, i)) c1.send(i) # 将i的值传给yield c2.send(i) # 将i的值传给yield producer("老板")
2.装饰器(decorator)
类似于一种动态增加函数功能的方法,使用@语法,放在它要装饰的函数定义处(函数定义的上面),实现为已经存在的函数增加新的功能。
Python通过使用装饰器来达到代码的开放与封闭。
@d1 def func(): pass 相当于d1(func),把func函数当成是参数传进d1。
def login(func): print("这是验证功能。。。") return func def home(): print("This is the Home page.") def tv(): print("This is the TV page") # 需求是在访问tv页面之前加上验证功能。 tv = login(tv) tv()
上述方法虽然可以实现需求,但是把tv函数改变了,而且当login函数需要传入参数的时候,就不好处理了。下面是使用装饰器来实现:
def login(func): def inner(): print("正在验证!。。。") func() print("welcome to the tv page!") return inner @login def tv(): print("This is the tv page!") tv()
当代码运行到@login时,会把它下面装饰的tv函数作为自己的参数,此时即:func = tv
当tv()执行时,实际上执行inner()。
当被装饰的函数需要多个参数时:
def login(func): def inner(*args): print("正在验证!。。。") func(*args) print("Have a nice time!") return inner @login def movie(*args): print("welcome {} to the {} page of movie!".format(*args)) movie("Alex", '3rd')
当被装饰的函数有返回值时,怎么处理呢?
# 当被装饰的函数有返回值时: def login(func): def inner(*args): print("正在验证!。。。") tmp = func(*args) print("Have a nice time!") return tmp # 注意:此处应该将被装饰函数的返回值return return inner @login def movie(*args): print("welcome {} to the {} page of movie!".format(*args)) return 666 # 被装饰的函数有返回值 num = movie("Alex", '3rd') print(num)
装饰器也可以有自己的参数:
def login(): print("开始进行验证。。。") def errorhandle(): print("出错啦。。。") # 给装饰器加参数 复杂的装饰器 def f(arg): def outer(main_func): def inner(): arg() main_func() return inner return outer @f(errorhandle) # @f(login) # 给装饰器传入不同的函数,被装饰的函数就扩展了不同的功能。 def index(): print("这是主程序。") index()
其实这就相当于写了一个装饰器的框架,以后有新的需求就只需把新写的函数当成参数传到装饰器框架中就可以了。
def login(): print("开始进行验证。。。") def errorhandle(): print("出错啦。。。") # 复杂的装饰器(装饰器框架) def f(before_func, after_func): # 第一层传入装饰器的参数 def outer(main_func): # 第二层传入被装饰的函数名 def inner(*args): # 第三层传入被装饰函数的参数 before_func() main_func(*args) after_func() return inner return outer @f(login, errorhandle) def index(name): print("{}:这是主程序。".format(name)) index('alex')
3.递归
递归其实就是函数自己调用自己的过程。使用递归时应该避免栈溢出。(使用尾递归防止栈溢出)
def calc(n): print(n) if n / 2 > 1: res = calc(n/2) # 在函数内部调用自己 print("res:{}".format(res)) print("n:{}".format(n)) return n
斐波那契数列:
# 斐波那契数列练习 def func(arg1, arg2, stop): if arg1 == 0: print(arg1) print(arg2) arg3 = arg1 + arg2 if arg3 < stop: print(arg3) func(arg2, arg3, stop)
二分法:
# 二分法查找find_num在不在data_base中: def binary_search(data_base, find_num): mid = int(len(data_base)/2) if len(data_base) > 1: if data_base[mid] > find_num: binary_search(data_base[:mid], find_num) elif data_base[mid] < find_num: binary_search(data_base[mid:], find_num) else: print("找到了!") elif len(data_base) == 1: if data_base[0] == find_num: print("找到了!") else: print("没找到!") else: print("没找到!") data_base = list(range(0, 10000000, 4)) binary_search(data_base, 2)
汉诺塔:
# 汉诺塔游戏 # n:A柱上有多少个盘子,a:左边的柱子,b:中间的柱子,c:右边的柱子 # 把左边柱子上的n个盘子移动到右边的柱子的详细步骤,盘子分大小,小盘子只能放在比他大的盘子上。 def mov_h(n, a, b, c): if n == 1: print("{}==>{}".format(a, c)) elif n > 1: mov_h(n-1, a, c, b) mov_h(1, a, b, c) mov_h(n-1, b, a, c) else: print("参数错误!") mov_h(5, 'A', 'B', 'C')
4.算法基础(二维数组转换)
打印一个4*4的二维数组:
# 打印一个二维数组: list_demo = [[i for i in range(4)] for i in range(4)] for i in list_demo: print(i) ================================= 显示: [0, 1, 2, 3] [0, 1, 2, 3] [0, 1, 2, 3] [0, 1, 2, 3]
现在想让这个二维数组顺时针旋转90度打印出来:
for i in range(len(list_demo)): for j in range(i, len(list_demo)): list_demo[i][j], list_demo[j][i] = list_demo[j][i], list_demo[i][j] =================================== 结果: [0, 0, 0, 0] [1, 1, 1, 1] [2, 2, 2, 2] [3, 3, 3, 3]
冒泡排序:
data = [10, 4, 33, 21, 54, 3, 8, 11, 5, 22, 2, 1, 17, 13, 6] count = 0 for i in range(len(data)-1): count += 1 for j in range(i, len(data)): count += 1 if data[i] > data[j]: data[j], data[i] = data[i], data[j] print(data) print(count) ============================================== 结果: [1, 2, 3, 4, 5, 6, 8, 10, 11, 13, 17, 21, 22, 33, 54] 133
5.正则表达式
正则表达式就是代码界的瑞士军刀!
正则表达式是一种用来匹配字符串的强有力的武器。它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的。
Python中的re模块,包含了正则表达式的所有功能。
正则表达式的五种常用模式:
1.re.match(pattern, string, flags=0) # 只匹配字符串的开头
p = re.compile(r'^[0-9]') # 生成正则对象,提前解析匹配规则 m = p.match("1234Abc") # match匹配到时返回一个Match对象,否则返回None n = p.match("Abc1234") # match只匹配字符串的开头 print("m:{}".format(m)) print("n:{}".format(n)) t = re.match(r'[0-9]+', "234abc234") print("t:{}".format(t)) =============================================== 结果: m:<_sre.SRE_Match object; span=(0, 1), match='> n:None t:<_sre.SRE_Match object; span=(0, 3), match='>
# re匹配中文,中文Unicode中中文编码为\u4e00-\u9fa5 contact = "我是中文" result = re.match(r'[\u4e00-\u9fa5]{2}', contact) if result: print(result.group()) ============================================== 结果: 我是
2.re.search(pattern, string, flags=0) # 匹配整个字符串,直到找到第一个匹配对象
p = re.compile(r'[0-9]+') # 生成正则对象,提前解析匹配规则 m = p.search("1234Abc5678Abc") # search匹配整个字符串并返回第一个匹配到的对象,否则返回None n = p.search("Abc1234Abc5678") # search匹配整个字符串 print("m:{}".format(m)) print("n:{}".format(n)) ============================================== 结果: m:<_sre.SRE_Match object; span=(0, 4), match='> n:<_sre.SRE_Match object; span=(3, 7), match='>
3.re.split(pattern, string, maxsplit=0, flags=0) # 用匹配到的对象将字符串分割成列表并返回
content = "Abc123.aBc456.abC789" result = re.split(r'\.', content) result2 = re.split(r'\.', content, 1) result3 = re.split(r'[\.\d]+', content) print("result:{}".format(result)) print("result2:{}".format(result2)) print("result3:{}".format(result3)) ============================================== 结果: result:['Abc123', 'aBc456', 'abC789'] result2:['Abc123', 'aBc456.abC789'] result3:['Abc', 'aBc', 'abC', '']
4.re.findall(pattern, string, flags=0) # 找到所有的匹配对象,以列表形式返回
content = "Abc123.aBc456.abC789" result = re.findall(r'\d+', content) # 找到所有的匹配,并以列表形式返回 print("result:{}".format(result)) ============================================== 结果: result:[']
5.re.sub(pattern, repl, string, count=0,flag=0) # 替换匹配到的对象
content = "1234Abc5678Abc" result = re.sub(r'\d+', "哈哈", content) result2 = re.sub(r'\d+', "哈哈", content, 1) print("result:{}".format(result)) print("result2:{}".format(result2)) ============================================== 结果: result:哈哈Abc哈哈Abc result2:哈哈Abc5678Abc
字符 | |
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线或汉字 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
实例 | 描述 |
---|---|
[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+} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
实例 | 描述 |
---|---|
. | 匹配除 "\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_]'。 |
匹配手机号码:
# 从字符串中查找手机号码 info = "hey my name is alex, and my phone number is 18651054604, please call me if you are pretty!" result = re.search(r'(1)[3578]\d{9}', info) if result: print(result.group()) # 匹配输入的是否为正确的手机号格式 phone_num = input("Please input your phone number:") result2 = re.match(r'^1[3578]\d{8}[0-9]$', phone_num) if result2: print("Your phone number is {}.".format(result2.group())) else: print("Invalid number.")
IP:
# 字符串中查找IP ip_addr = "inet 192.168.60.223 netmask 0xffffff00 broadcast 192.168.60.255" p = re.compile(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') result = p.search(ip_addr) if result: print(result.group()) # 判断输入是否为合法IP ip_info = input("Please input the IP:").strip() result2 = re.search(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$', ip_info) if result2: print("Your IP is: {}".format(result2.group())) else: print("Invalid input")
分组匹配:
contactInfo = "Oldboy School, Beijing Changping Shahe: 010-8343245" match = re.search(r'(.+), (.+): (\S+)', contactInfo) if match: print("get it!") print(match.group(0)) # group(0)指的是原始字符串 print(match.group(1)) # group(1)指的是第1个子串 print(match.group(2)) # group(2)指的是第2个子串 print(match.group(3)) # group(3)指的是第3个子串 else: print("error")
命名的分组匹配:
contactInfo = "Oldboy School, Beijing Changping Shahe: 010-8343245" match = re.search(r'(?P<name>.+), (?P<addr>.+): (?P<tel>\S+)', contactInfo) if match: print(match.group('name')) print(match.group('addr')) print(match.group('tel')) else: print("error") ============================================== 结果: Oldboy School Beijing Changping Shahe 010-8343245
email地址匹配:
# 字符串中查找email email_info = "Hey guy, my email address is master@liwenzhou.com, send mail to me!" match = re.search(r'([a-z0-9])[a-z.0-9]{0,25}@[a-z.0-9]{1,20}.[a-z0-9]{1,8}', email_info) if match: print(match.group()) # 匹配输入是否为有效email地址 email = input("Please input your email:").strip() result = re.match(r'^([a-z.0-9]{1,26})@([a-z.0-9]{1,20})(.[a-z0-9]{1,8})$', email) if result: print("Your email is: {}".format(result.group())) else: print("Invalid input!")
编译标志
编译标志让你可以修改正则表达式的一些运行方式。在 re 模块中标志可以使用两个名字,一个是全名如 IGNORECASE,一个是缩写,一字母形式如 I。(如果你熟悉 Perl 的模式修改,一字母形式使用同样的字母;例如 re.VERBOSE的缩写形式是 re.X。)多个标志可以通过按位 OR-ing 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
这有个可用标志表,对每个标志後面都有详细的说明。
标志 | 含义 |
DOTALL, S | 使 . 匹配包括换行在内的所有字符 |
IGNORECASE, I | 使匹配对大小写不敏感 |
LOCALE, L | 做本地化识别(locale-aware)匹配 |
MULTILINE, M | 多行匹配,影响 ^ 和 $ |
VERBOSE, X | 能够使用 REs 的 verbose 状态,使之被组织得更清晰易懂 |
I
IGNORECASE
使匹配对大小写不敏感;字符类和字符串匹配字母时忽略大小写。举个例子,[A-Z]也可以匹配小写字母,Spam 可以匹配 "Spam", "spam", 或 "spAM"。这个小写字母并不考虑当前位置。
L
LOCALE
影响 "w, "W, "b, 和 "B,这取决于当前的本地化设置。
locales 是 C 语言库中的一项功能,是用来为需要考虑不同语言的编程提供帮助的。举个例子,如果你正在处理法文文本,你想用 "w+ 来匹配文字,但 "w 只匹配字符类 [A-Za-z];它并不能匹配 "é" 或 "ç"。如果你的系统配置适当且本地化设置为法语,那么内部的 C 函数将告诉程序 "é" 也应该被认为是一个字母。当在编译正则表达式时使用 LOCALE 标志会得到用这些 C 函数来处理 "w 後的编译对象;这会更慢,但也会象你希望的那样可以用 "w+ 来匹配法文文本。
M
MULTILINE
(此时 ^ 和 $ 不会被解释; 它们将在 4.1 节被介绍.)
使用 "^" 只匹配字符串的开始,而 $ 则只匹配字符串的结尾和直接在换行前(如果有的话)的字符串结尾。当本标志指定後, "^" 匹配字符串的开始和字符串中每行的开始。同样的, $ 元字符匹配字符串结尾和字符串中每行的结尾(直接在每个换行之前)。
S
DOTALL
使 "." 特殊字符完全匹配任何字符,包括换行;没有这个标志, "." 匹配除了换行外的任何字符。
X
VERBOSE
该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。当该标志被指定时,在 RE 字符串中的空白符被忽略,除非该空白符在字符类中或在反斜杠之後;这可以让你更清晰地组织和缩进 RE。它也可以允许你将注释写入 RE,这些注释会被引擎忽略;注释用 "#"号 来标识,不过该符号不能在字符串或反斜杠之後。
<==the end