what's the python之模块
Posted ゛竹先森゜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了what's the python之模块相关的知识,希望对你有一定的参考价值。
正则表达式
首先,我们引入了正则表达式的知识。所谓正则表达式,就是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
正则表达式本身和python没有什么关系,就是匹配字符串内容的一种规则。这里给了一个非常好用的在线测试工具http://tool.chinaz.com/regex/
谈到正则,就只和字符串相关了。着眼于正则的时候,输入的每一个字都是一个字符串。如果在一个位置的一个值,不会出现什么变化,那么是不需要规则的,直接就可以匹配上。在之后我们更多要考虑的是在同一个位置上可以出现的字符的范围。
字符组 : 形式为——[字符组]
在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用[ ]表示字符分为很多类,比如数字、字母、标点等等。假如你现在要求一个位置"只能出现一个数字",那么这个位置上的字符只能是0、1、2...9这10个数之一。可以用[0123456789]表达,也可以用[0-9],后者只能从小指到大,即不可以用[9-0]的形式。
|
以下是正则表达式中的所有字符及其用法:
元字符 | 匹配内容 |
. | 匹配除换行符以外的任意字符 |
\\w | 匹配字母或数字或下划线或汉字 |
\\s | 匹配任意的空白符 |
\\d | 匹配数字 |
\\n | 匹配一个换行符 |
\\t | 匹配一个制表符 |
\\b | 匹配一个单词的结尾 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结尾 |
\\W |
匹配非字母或数字或下划线或汉字,即除\\w能匹配的类型以外的所有类型 |
\\D |
匹配非数字,即除\\d能匹配的类型以外的所有类型 |
\\S |
匹配非空白符,即除\\s能匹配的类型以外的所有类型 |
a|b |
匹配字符a或字符b |
() |
匹配括号内的表达式,也表示一个组 |
[...] |
匹配字符组中的字符 |
[^...] |
匹配除了字符组中字符的所有字符,即与[]相反 |
|
. ^ $的用法简介
正则 | 待匹配字符 | 匹配 结果 |
说明 |
海. | 海燕海东西海娇 |
海燕 海东 海娇 |
匹配所有"海."的字符 |
^海. | 海燕海东西海娇 | 海燕 | 只从开头匹配"海." |
海.$ | 海燕海东西海娇 | 海娇 | 只匹配结尾的"海.$" |
* + ? { }的用法简介
正则 | 待匹配字符 | 匹配 结果 |
说明 |
李.? | 李杰和李莲英和李二棍子 |
李杰 |
?表示重复零次或一次,即只匹配"李"后面一个任意字符,贪婪匹配 |
李.* | 李杰和李莲英和李二棍子 | 李杰和李莲英和李二棍子 |
*表示重复零次或多次,即匹配"李"后面0或多个任意字符,贪婪匹配 |
李.+ | 李杰和李莲英和李二棍子 | 李杰和李莲英和李二棍子 |
+表示重复一次或多次,即只匹配"李"后面1个或多个任意字符,贪婪匹配 |
李.{1,2} | 李杰和李莲英和李二棍子 |
李杰和 |
{1,2}匹配1到2次任意字符,贪婪匹配 |
注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
正则 | 待匹配字符 | 匹配 结果 |
说明 |
李.*? | 李杰和李莲英和李二棍子 | 李杰 李莲 李二 |
惰性匹配 |
字符集[][^]的用法简介
正则 | 待匹配字符 | 匹配 结果 |
说明 |
李[杰莲英二棍子]* | 李杰和李莲英和李二棍子 |
李杰 |
表示匹配"李"字后面[杰莲英二棍子]的字符任意次 |
李[^和]* | 李杰和李莲英和李二棍子 |
李杰 |
表示匹配一个不是"和"的字符任意次 |
[\\d] | 456bdha3 |
4 |
表示匹配任意一个数字,匹配到4个结果 |
[\\d]+ | 456bdha3 |
456 |
表示匹配任意个数字,匹配到2个结果 |
分组 ()与 或 |[^]的用法简介
身份证号码是一个长度为15或18个字符的字符串,如果是15位则全部由数字组成,首位不能为0;如果是18位,则前17位全部是数字,末位可能是数字或x,下面我们尝试用正则来表示:
正则 | 待匹配字符 | 匹配 结果 |
说明 |
^[1-9]\\d{13,16}[0-9x]$ | 110101198001017032 |
110101198001017032 |
表示可以匹配一个正确的身份证号 |
^[1-9]\\d{13,16}[0-9x]$ | 1101011980010170 |
1101011980010170 |
表示也可以匹配这串数字,但这并不是一个正确的身份证号码,它是一个16位的数字 |
^[1-9]\\d{14}(\\d{2}[0-9x])?$ | 1101011980010170 |
False |
现在不会匹配错误的身份证号了 |
^([1-9]\\d{16}[0-9x]|[1-9]\\d{14})$ | 110105199812067023 |
110105199812067023 |
表示先匹配[1-9]\\d{16}[0-9x]如果没有匹配上就匹配[1-9]\\d{14} |
转义符 \\的用法简介
在正则表达式中,有很多有特殊意义的是元字符,比如\\d和\\s等,如果要在正则中匹配正常的"\\d"而不是"数字"就需要对"\\"进行转义,变成\'\\\\\'。
在python中,无论是正则表达式,还是待匹配的内容,都是以字符串的形式出现的,在字符串中\\也有特殊的含义,本身还需要转义。所以如果匹配一次"\\d",字符串中要写成\'\\\\d\',那么正则里就要写成"\\\\\\\\d",这样就太麻烦了。这个时候我们就用到了r\'\\d\'这个概念,此时的正则是r\'\\\\d\'就可以了。
正则 | 待匹配字符 | 匹配 结果 |
说明 |
\\d | \\d | False |
因为在正则表达式中\\是有特殊意义的字符,所以要匹配\\d本身,用表达式\\d无法匹配 |
\\\\d | \\d | True |
转义\\之后变成\\\\,即可匹配 |
"\\\\\\\\d" | \'\\\\d\' | True |
如果在python中,字符串中的\'\\\'也需要转义,所以每一个字符串\'\\\'又需要转义一次 |
r\'\\\\d\' | r\'\\d\' | True |
在字符串之前加r,让整个字符串不转义 |
贪婪匹配
贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配
正则 | 待匹配字符 | 匹配 结果 |
说明 |
<.*> |
<script>...<script> |
<script>...<script> |
默认为贪婪匹配模式,会匹配尽量长的字符串 |
<.*?> | r\'\\d\' |
<script> |
加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串 |
注:在后面加上?后即转为非贪婪匹配模式,所有匹配长度都取最短
附:非贪婪模式的一个用法—— .*?x 就是取前面任意长度的字符,直到一个x出现
re模块下的常用方法
import re ret = re.findall(\'a\', \'eva egon yuan\') # 返回所有满足匹配条件的结果,放在列表里 print(ret) #结果 : [\'a\', \'a\'] ret = re.search(\'a\', \'eva egon yuan\').group() print(ret) #结果 : \'a\' # 函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以 # 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。 ret = re.match(\'a\', \'abc\').group() # 同search,不过仅在字符串开始处进行匹配,如果开始没有匹配到就报错 print(ret) #结果 : \'a\' ret = re.split(\'[ab]\', \'abcd\') # 先按\'a\'分割得到\'\'和\'bcd\',在对\'\'和\'bcd\'分别按\'b\'分割 print(ret) # [\'\', \'\', \'cd\'] ret = re.sub(\'\\d\', \'H\', \'eva3egon4yuan4\', 1)#将数字替换成\'H\',参数1表示只替换1个 print(ret) #evaHegon4yuan4 ret = re.subn(\'\\d\', \'H\', \'eva3egon4yuan4\')#将数字替换成\'H\',返回元组(替换的结果,替换了多少次) print(ret)#(\'evaHegonHyuanH\', 3) obj = re.compile(\'\\d{3}\') #将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字 ret = obj.search(\'abc123eeee\') #正则表达式对象调用search,参数为待匹配的字符串 print(ret.group()) #结果 : 123 import re ret = re.finditer(\'\\d\', \'ds3sy4784a\') #finditer返回一个存放匹配结果的迭代器 print(ret) # <callable_iterator object at 0x10195f940> print(next(ret).group()) #查看第一个结果即3 print(next(ret).group()) #查看第二个结果即4 print([i.group() for i in ret]) #查看剩余的结果,以列表的形式打印,即[\'7\', \'8\', \'4\']
注意:findall和split的优先级查询:
#1 findall的优先级查询: import re ret = re.findall(\'www.(sogo|baidu).com\', \'www.baidu.com\') print(ret) # [\'baidu\'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可 ret = re.findall(\'www.(?:sogo|baidu).com\', \'www.baidu.com\') print(ret) # [\'www.baidu.com\'] #2 split的优先级查询 ret=re.split("\\d+","eva3egon4yuan") print(ret) #结果 : [\'eva\', \'egon\', \'yuan\'] ret=re.split("(\\d+)","eva3egon4yuan") print(ret) #结果 : [\'eva\', \'3\', \'egon\', \'4\', \'yuan\'] #在匹配部分加上()之后所切出的结果是不同的, #没有()的没有保留所匹配的项,但是有()的却能够保留了匹配的项, #这个在某些需要保留匹配部分的使用过程是非常重要的。
下面举几个练习的栗子,需要了解,为了变得更牛逼出去更好的装逼最好还是掌握:
1、匹配标签
import re ret = re.search("<(?P<tag_name>\\w+)>\\w+</(?P=tag_name)>","<h1>hello</h1>") #还可以在分组中利用?<name>的形式给分组起名字 #获取的匹配结果可以直接用group(\'名字\')拿到对应的值 print(ret.group(\'tag_name\')) #结果 :h1 print(ret.group()) #结果 :<h1>hello</h1> ret = re.search(r"<(\\w+)>\\w+</\\1>","<h1>hello</h1>") #如果不给组起名字,也可以用\\序号来找到对应的组,表示要找的内容和前面的组内容一致 #获取的匹配结果可以直接用group(序号)拿到对应的值 print(ret.group(1)) print(ret.group()) #结果 :<h1>hello</h1>
2、匹配整数
import re ret=re.findall(r"\\d+","1-2*(60+(-40.35/5)-(-4*3))") print(ret) #[\'1\', \'2\', \'60\', \'40\', \'35\', \'5\', \'4\', \'3\'] ret=re.findall(r"-?\\d+\\.\\d*|(-?\\d+)","1-2*(60+(-40.35/5)-(-4*3))") print(ret) #[\'1\', \'-2\', \'60\', \'\', \'5\', \'-4\', \'3\'] ret.remove("") print(ret) #[\'1\', \'-2\', \'60\', \'5\', \'-4\', \'3\'] ret=re.findall(r\'(-?\\d+\\.\\d*)|-?\\d+\',\'1-2*(60+(-40.35/5)-(-4*3))\') print(ret)#[\'\', \'\', \'\', \'-40.35\', \'\', \'\', \'\'] ret=re.findall(r\'-?\\d+\\.\\d*|-?\\d+\',\'1-2*(60+(-40.35/5)-(-4*3))\') print(ret)#[\'1\', \'-2\', \'60\', \'-40.35\', \'5\', \'-4\', \'3\']
3、数字匹配
1、 匹配一段文本中的每行的邮箱 http://blog.csdn.net/make164492212/article/details/51656638 2、 匹配一段文本中的每行的时间字符串,比如:‘1990-07-12’; 分别取出1年的12个月(^(0?[1-9]|1[0-2])$)、 一个月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$ 3、 匹配qq号。(腾讯QQ号从10000开始) [1,9][0,9]{4,} 4、 匹配一个浮点数。 ^(-?\\d+)(\\.\\d+)?$ 或者 -?\\d+\\.?\\d* 5、 匹配汉字。 ^[\\u4e00-\\u9fa5]{0,}$ 6、 匹配出所有整数
4、爬虫练习
import requests import re import json def getPage(url): response=requests.get(url) return response.text def parsePage(s): com=re.compile(\'<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\\d+).*?<span class="title">(?P<title>.*?)</span>\' \'.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>\',re.S) ret=com.finditer(s) for i in ret: yield { "id":i.group("id"), "title":i.group("title"), "rating_num":i.group("rating_num"), "comment_num":i.group("comment_num"), } def main(num): url=\'https://movie.douban.com/top250?start=%s&filter=\'%num response_html=getPage(url) ret=parsePage(response_html) print(ret) f=open("move_info7","a",encoding="utf8") for obj in ret: print(obj) data=json.dumps(obj,ensure_ascii=False) f.write(data+"\\n") if __name__ == \'__main__\': count=0 for i in range(10): main(count) count+=25
关于正则的知识目前就到这里,下面要说有关模块的知识
what\'s the 是模块?
一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。
但其实import加载的模块分为四个通用类别:
1 使用python编写的代码(.py文件)
2 已被编译为共享库或DLL的C或C++扩展
3 包好一组模块的包
4 使用C编写并链接到python解释器的内置模块
为何要使用模块?
如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py被称为脚本script。
随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用。
模块的导入应该在程序的起始位置。格式为import +模块名
首先我们学了re模块,re模块与正则表达式息息相关,关于re模块的使用,在上文正则表达式中就有提及,即findall、search和match的使用方法,这里不做赘述。
然后我们来看看关于collection模块。
collection模块
在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。
1.namedtuple: 生成可以使用名字来访问元素内容的tuple
2.deque: 双端队列,可以快速的从另外一侧追加和推出对象
3.Counter: 计数器,主要用来计数
4.OrderedDict: 有序字典
5.defaultdict: 带有默认值的字典
下面我们来详细介绍一下这5种数据类型:
namedtuple:主要用在坐标上表示,如表示一个点或者一个圆
from collections import namedtuple Point = namedtuple(\'Point\', [\'x\', \'y\']) p = Point(1, 2) p.x p.y #表示圆 #namedtuple(\'名称\', [属性list]): Circle = namedtuple(\'Circle\', [\'x\', \'y\', \'r\'])
deque:
因为list是线性存储,数据量大的时候,插入和删除效率很低。deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:
from collections import deque q = deque([\'a\', \'b\', \'c\']) q.append(\'x\') q.appendleft(\'y\') print(q)#[\'y\', \'a\', \'b\', \'c\', \'x\']
注:deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素。
OrderedDict:使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。如果要保持Key的顺序,可以用OrderedDict
from collections import OrderedDict d = dict([(\'a\', 1), (\'b\', 2), (\'c\', 3)])# dict的Key是无序的 print(d)#{\'a\': 1, \'c\': 3, \'b\': 2} od = OrderedDict([(\'a\', 1), (\'b\', 2), (\'c\', 3)])# OrderedDict的Key是有序的 print(od)#OrderedDict([(\'a\', 1), (\'b\', 2), (\'c\', 3)])
注:OrderedDict的Key会按照插入的顺序排列,不是按照Key本身排序
defaultdict:使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict
from collections import defaultdict dd=defaultdict(lambda :\'N/A\')#即key不存在时返回设置的默认值 dd[\'k1\']=\'abc\' print(dd[\'k1\'])#abc print(dd[\'k2])#N/A
拿defaultdict举个小栗子:
#有如下值集合 [11,22,33,44,55,66,77,88,99,90...],将所有大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中。 #即: {\'k1\': 大于66 , \'k2\': 小于66} #利用字典的解决方式: l= [11, 22, 33,44,55,66,77,88,99,90] my_dict = {} for value in l: if value>66: if my_dict.has_key(\'k1\'): my_dict[\'k1\'].append(value) else: my_dict[\'k1\'] = [value] else: if my_dict.has_key(\'k2\'): my_dict[\'k2\'].append(value) else: my_dict[\'k2\'] = [value] #利用defaultdict的解决方法: from collections import defaultdict l= [11, 22, 33,44,55,66,77,88,99,90] my_dict = defaultdict(list) for value in l: if value>66: my_dict[\'k1\'].append(value) else: my_dict[\'k2\'].append(value)
Counter:Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。
c = Counter(\'abcdeabcdabcaba\') print c #Counter({\'a\': 5, \'b\': 4, \'c\': 3, \'d\': 2, \'e\': 1})
时间模块
在Python中,通常有这三种方式来表示时间:时间戳(timestamp)、元组(struct_time)、格式化的时间字符串(Format String)
(1)时间戳(timestamp) :通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
(2)格式化的时间字符串(Format String):表现形式为 ‘1999-12-06’,下文会详细介绍
(3)元组(struct_time) :struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天和是否是夏令时)
注:时间戳是计算机能够识别的时间;时间字符串是人能够看懂的时间;元组则是用来操作时间的
索引(Index) | 属性(Attribute) | 值(Values) |
---|---|---|
0 | tm_year(年) | 比如2011 |
1 | tm_mon(月) | 1 - 12 |
2 | tm_mday(日) | 1 - 31 |
3 | tm_hour(时) | 0 - 23 |
4 | tm_min(分) | 0 - 59 |
5 | tm_sec(秒) | 0 - 61 |
6 | tm_wday(weekday) | 0 - 6(0表示周日) |
7 | tm_yday(一年中的第几天) | 1 - 366 |
8 | tm_isdst(是否是夏令时) | 默认为-1 |
import time #时间戳 print(time.time())#1502179789.9325476 #时间字符串,%都有对应的意思 print(time.strftime(\'%Y-%m-%d %X\'))#2017-08-08 16:09:49 #时间元祖 print(time.localtime())#time.struct_time(tm_year=2017, tm_mon=8, tm_mday=8, tm_hour=16, tm_min=9, tm_sec=49, tm_wday=1, tm_yday=220, tm_isdst=0)
有关于时间字符串中的格式化符号,具体如下:
%y 两位数的年份表示(00-99) %Y 四位数的年份表示(000-9999) %m 月份(01-12) %d 月内中的一天(0-31) %H 24小时制小时数(0-23) %I 12小时制小时数(01-12) %M 分钟数(00=59) %S 秒(00-59以上是关于what's the python之模块的主要内容,如果未能解决你的问题,请参考以下文章