Python之路day4
坚持就是胜利。今天零下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
Python之路day4的更多相关文章
- Python之路,Day4 - Python基础4 (new版)
Python之路,Day4 - Python基础4 (new版) 本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 ...
- 小白的Python之路 day4 装饰器前奏
装饰器前奏: 一.定义: 1.装饰器本质是函数,语法都是用def去定义的 (函数的目的:他需要完成特定的功能) 2.装饰器的功能:就是装饰其他函数(就是为其他函数添加附加功能) 二.原则: 1. 不能 ...
- Python之路,Day4 - Python基础4
一.函数 (一)背景提要 现在老板让你写一个监控程序,监控服务器的系统状况,当cpu\memory\disk等指标的使用量超过阀值时即发邮件报警,你掏空了所有的知识量,写出了以下代码 1 2 3 4 ...
- python之路-Day4
本节内容 1. 函数基本语法及特性 2. 参数与局部变量 3. 返回值 嵌套函数 4.递归 5.匿名函数 6.函数式编程介绍 7.高阶函数 8.内置函数 函数是什么? 函数一词来源于数学,但编程中的「 ...
- 小白的Python之路 day4 装饰器高潮
首先装饰器实现的条件: 高阶函数+嵌套函数 =>装饰器 1.首先,我们先定义一个高级函数,去装饰test1函数,得不到我们想要的操作方式 import time #定义高阶函数 def deco ...
- 小白的Python之路 day4 生成器
一.列表生成式 看下面例子: 列表生成式的作用:主要是让代码更简洁(还有装X的效果) 二.生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包 ...
- 小白的Python之路 day4 迭代器
迭代器 学习前,我们回想一下可以直接作用于for循环的数据类型有以下几种: 1.集合数据类型,如list.tuple.dict.set.str等: 2.是generator,包括生成器和带yield的 ...
- 小白的Python之路 day4 json and pickle数据标准序列化
一.简述 我们在写入文件中的数据,只能是字符串或者二进制,但是要传入文件的数据不一定全是字符串或者二进制,那还要进行繁琐的转换,然后再读取的时候,还要再转回去,显得很麻烦,今天就来学习标准的序列化:j ...
- 小白的Python之路 day4 软件目录结构规范
软件目录结构规范 为什么要设计好目录结构? "设计项目目录结构",就和"代码编码风格"一样,属于个人风格问题.对于这种风格上的规范,一直都存在两种态度: 一类同 ...
随机推荐
- 用Html5结合Qt制作一款本地化EXE游戏-太空大战(Space War)
本次来说一说如何利用lufylegend.js引擎制作一款html5游戏后将其通过Qt转换成EXE程序.步骤其实非常简单,接下来就一步步地做一下解释和说明. 首先我们来开发一个有点类似于太空大战的游戏 ...
- UIControl IOS控件编程 及UITextField的讲解
第一部分 UIKit提供了一组控件:UISwitch开关.UIButton按钮.UISegmentedControl分段控件.UISlider滑块.UITextField文本字段控件.UIPageCo ...
- Js 返回页面 or 跳转页面
跳出 iframe 在当前页跳转, window.parent.frames.location.href=www.baidu.com" 跳转页面 onclick="history. ...
- VPN连接在遇到飞鱼星设备时可能出现的疑难问题
在连接VPN设备时,设置都是正常的.在
- UIButton 动态改变文本闪烁问题
当动态改变(比如一秒改变一次)按钮的Title的时候发现按钮每次都要闪烁一下:解决方法如下: self.settleButton.titleLabel.text = title; [self.sett ...
- Unity 对象池 生产 保存
Unity对象池主要是保存那些常用的物体,避免他们在不断销毁和创造中损坏性能. 主要思路为:创造物体时,判断是否存在,如果存在则调用并使其显示.如果不存在则创造一个新的. 当销毁时,调用协程延时隐藏物 ...
- FreeCodeCamp:Title Case a Sentence
要求: 确保字符串的每个单词首字母都大写,其余部分小写. 像'the'和'of'这样的连接符同理. 结果: titleCase("I'm a little tea pot") 应该 ...
- JDBC----数据库连接池(connection pool)
•数据库连接池的基本思想就是为数据库连接建立一个"缓冲池".预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从"缓冲池"中取出一个,使用完毕之后再 ...
- FPGA知识大梳理(二)verilogHDL语法入门(1)
此文是写给0基础学习者,也是对自己知识点总结水平的考验. 对于有C基础的人来说,学习verilog应该是轻而易举 —— 类比法学习. 第一步:格式. 对于C来说我们前面会写 ‘include“std ...
- C++ ABI之名字改变,编译器生成符号研究(以Qt为例)
在C++中,由于重载等技术的存在,编译器要将函数.结构体.类等等的信息传递给链接器,就不能像C语言那样简单地通过函数名来完成,它需要提供额外的参数信息,而还要和C语言共用链接器,这就需要用到名字改编( ...