what's the python之模塊


 

正則表達式

  首先,我們引入了正則表達式的知識。所謂正則表達式,就是對字符串操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個“規則字符串”,這個“規則字符串”用來表達對字符串的一種過濾邏輯。

  正則表達式本身和python沒有什么關系,就是匹配字符串內容的一種規則。這里給了一個非常好用的在線測試工具http://tool.chinaz.com/regex/

  談到正則,就只和字符串相關了。着眼於正則的時候,輸入的每一個字都是一個字符串。如果在一個位置的一個值,不會出現什么變化,那么是不需要規則的,直接就可以匹配上。在之后我們更多要考慮的是在同一個位置上可以出現的字符的范圍。

  字符組 : 形式為——[字符組]

  在同一個位置可能出現的各種字符組成了一個字符組,在正則表達式中用[ ]表示字符分為很多類,比如數字、字母、標點等等。假如你現在要求一個位置"只能出現一個數字",那么這個位置上的字符只能是0、1、2...9這10個數之一。可以用[0123456789]表達,也可以用[0-9],后者只能從小指到大,即不可以用[9-0]的形式。

字符組
待匹配字符
匹配
結果
說明
[0123456789]
8
True
在一個字符組里枚舉合法的所有字符,字符組里的任意一個字符
和"待匹配字符"相同都視為可以匹配
[0123456789]
a
False
由於字符組中沒有"a"字符,所以不能匹配
 
[0-9]
 
7
True
[0-9]和[0123456789]是一個意思
 
[a-z]
 
s
 
True
 
同樣的如果要匹配所有的小寫字母,直接用[a-z]就可以表示
 
[A-Z]
 
B
 
True
 
[A-Z]就表示所有的大寫字母
 
[0-9][a-f][A-F]
 
e
 
True
 
可以匹配數字,大小寫形式的a~f,用來驗證十六進制字符

 

以下是正則表達式中的所有字符及其用法:

元字符 匹配內容
. 匹配除換行符以外的任意字符
\w 匹配字母或數字或下划線或漢字
\s 匹配任意的空白符
\d 匹配數字
\n 匹配一個換行符
\t 匹配一個制表符
\b 匹配一個單詞的結尾
^ 匹配字符串的開始
$ 匹配字符串的結尾
\W
匹配非字母或數字或下划線或漢字,即除\w能匹配的類型以外的所有類型
\D
匹配非數字,即除\d能匹配的類型以外的所有類型
\S
匹配非空白符,即除\s能匹配的類型以外的所有類型
a|b
匹配字符a或字符b
()
匹配括號內的表達式,也表示一個組
[...]
匹配字符組中的字符
[^...]
匹配除了字符組中字符的所有字符,即與[]相反

 

量詞
用法說明
* 重復零次或更多次
+ 重復一次或更多次
? 重復零次或一次
{n} 重復n次
{n,} 重復n次或更多次
{n,m} 重復n到m次

. ^ $的用法簡介

正則 待匹配字符 匹配
結果
說明
海. 海燕海東西海嬌

海燕

海東

海嬌

  匹配所有"海."的字符
^海. 海燕海東西海嬌 海燕 只從開頭匹配"海."
  海.$   海燕海東西海嬌 海嬌 只匹配結尾的"海.$"

 

* + ? { }的用法簡介

正則 待匹配字符 匹配
結果
說明
李.? 李傑和李蓮英和李二棍子

李傑
李蓮
李二

 
?表示重復零次或一次,即只匹配"李"后面一個任意字符,貪婪匹配
 
李.* 李傑和李蓮英和李二棍子 李傑和李蓮英和李二棍子
*表示重復零次或多次,即匹配"李"后面0或多個任意字符,貪婪匹配
李.+ 李傑和李蓮英和李二棍子 李傑和李蓮英和李二棍子
+表示重復一次或多次,即只匹配"李"后面1個或多個任意字符,貪婪匹配
李.{1,2} 李傑和李蓮英和李二棍子

李傑和
李蓮英
李二棍

{1,2}匹配1到2次任意字符,貪婪匹配

 注意:前面的*,+,?等都是貪婪匹配,也就是盡可能匹配,后面加?號使其變成惰性匹配

正則 待匹配字符 匹配
結果
說明
李.*? 李傑和李蓮英和李二棍子 李傑
李蓮
李二
惰性匹配

 

字符集[][^]的用法簡介

正則 待匹配字符 匹配
結果
說明
李[傑蓮英二棍子]* 李傑和李蓮英和李二棍子

李傑
李蓮英
李二棍子

 
表示匹配"李"字后面[傑蓮英二棍子]的字符任意次
 
李[^和]* 李傑和李蓮英和李二棍子

李傑
李蓮英
李二棍子

表示匹配一個不是"和"的字符任意次
[\d] 456bdha3

4
5
6
3

表示匹配任意一個數字,匹配到4個結果
[\d]+ 456bdha3

456
3

表示匹配任意個數字,匹配到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

現在不會匹配錯誤的身份證號了
()表示分組,將\d{2}[0-9x]分成一組,就可以整體約束他們出現的次數為0-1次
^([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>
<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>
View Code

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']
View Code

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、 匹配出所有整數
View Code

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
View Code

 

關於正則的知識目前就到這里,下面要說有關模塊的知識

 


 

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模塊的使用,在上文正則表達式中就有提及,即findallsearchmatch的使用方法,這里不做贅述。

  然后我們來看看關於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)
View Code

 

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%a 本地簡化星期名稱
%A 本地完整星期名稱
%b 本地簡化的月份名稱
%B 本地完整的月份名稱
%c 本地相應的日期表示和時間表示
%j 年內的一天(001-366%p 本地A.M.或P.M.的等價符
%U 一年中的星期數(00-53)星期天為星期的開始
%w 星期(0-6),星期天為星期的開始
%W 一年中的星期數(00-53)星期一為星期的開始
%x 本地相應的日期表示
%X 本地相應的時間表示
%Z 當前時區的名稱
%% %號本身

python中時間日期格式化符號:
View Code

 

幾種格式之間的轉換方式如下圖:

具體方法如下:

#時間戳轉化為結構化時間(元祖)-->time.gmtime()  time.localtime()
print(time.gmtime())#UTC時間,即格林尼治時間,與英國倫敦當地時間一致
print(time.localtime())#當地時間。例如我們現在在北京執行這個方法:與UTC時間相差8小時,UTC時間+8小時 = 北京時間
#如果括號內有參數,則輸出的是參數所代表的時間
print(time.gmtime(1500000000))#time.struct_time(tm_year=2017, tm_mon=7, tm_mday=14, tm_hour=2, tm_min=40, tm_sec=0, tm_wday=4, tm_yday=195, tm_isdst=0)
print(time.localtime(1500000000))#time.struct_time(tm_year=2017, tm_mon=7, tm_mday=14, tm_hour=10, tm_min=40, tm_sec=0, tm_wday=4, tm_yday=195, tm_isdst=0)

#結構化時間(元祖)轉化為時間戳-->time.mktime(結構化的時間)
print(time.mktime(time.localtime()))#1502180872.0

#結構化時間(元祖)轉換為字符串時間(格式化)-->time.strftime("格式定義","結構化時間")  結構化時間參數若不傳,則現實當前時間
print(time.strftime('%Y-%m-%d %X'))#2017-08-08 16:30:16
print(time.strftime("%Y-%m-%d %X",time.localtime(1500000000)))#2017-07-14 10:40:00

#字符串時間(格式化)轉化為結構化時間(元祖)-->time.strptime(時間字符串,字符串對應格式)
print(time.strptime("2017-03-16","%Y-%m-%d"))#time.struct_time(tm_year=2017, tm_mon=3, tm_mday=16, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=75, tm_isdst=-1)
print(time.strptime("07/24/2017","%m/%d/%Y"))#time.struct_time(tm_year=2017, tm_mon=7, tm_mday=24, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=205, tm_isdst=-1)

 

另外還有一種特別的轉換方式,如下圖:

具體方法如下:

#結構化時間(元祖)轉化為%a %b %d %H:%M:%S %Y串-->time.asctime(結構化時間),如果不傳參數,直接返回當前時間的格式化串
print(time.asctime())#Tue Aug  8 16:47:55 2017
print(time.asctime(time.localtime(1500000000)))#Tue Aug  8 16:47:55 2017

#%a %d %d %H:%M:%S %Y串轉化為結構化時間-->time.ctime(時間戳),如果不傳參數,直接返回當前時間的格式化串
print(time.ctime())#Tue Aug  8 16:49:54 2017
print(time.ctime(1500000000))#Fri Jul 14 10:40:00 2017

 

random模塊

  random模塊的作用就是隨機,可隨機生成整數、小數、字母,主要的應用方式是生成驗證碼。

import random
print(random.random())#隨機生成0-1之間的小數
print(random.uniform(1,3))#隨機生成1-3之間的小數
#
# 生成四個隨機整數:
l = []
l.append(str(random.randint(0,9)))
l.append(str(random.randint(0,9)))
l.append(str(random.randint(0,9)))
l.append(str(random.randint(0,9)))
print(''.join(l))#隨機四個數,如4041
print(l)#隨機四個數組成的列表,如['4', '0', '4', '1']

print(random.randint(1000,9999))#隨機生成1000-9999之間的整數,也可以視為給了四個隨機整數的一種方法
print(random.randrange(1,7,2))#也可以使用步距

ret = random.choice([1,2,'b',4,'a',6])
print(ret)#隨機從列表的元素中取出一個
ret = random.sample([1,2,'b',4,'a',6],3)
print(ret)#隨機從列表的元素中取出三個

l = list(range(100))
random.shuffle(l)#隨機打亂l中的順序,
print(l)

 

random模塊的一個重要應用場景是生成驗證碼,下面舉一個栗子:

#寫一個驗證碼,首先要有數字,其次要有字母,一共4位,可以重復
new_num_l = list(map(str,range(10)))  #['0','1'...'9']
# alph_l = []   #用來存字母
# for i in range(65,91):#查詢ascii碼得到英文字母A-Z對應的數字為65-90
#     alph = chr(i)
#     alph_l.append(alph)   #['A'..'Z']
alph_l = [chr(i) for i in range(65,91)]  #列表推導式
new_num_l.extend(alph_l)
Alph_l = [chr(i) for i in range(97,124)]
new_num_l.extend(Alph_l)
# ret_l = []   #存生成的隨機數字或字母
# for i in range(4):
#     ret_l.append(random.choice(new_num_l))
ret_l = [random.choice(new_num_l) for i in range(4)]
#ret_l中有4個元素
# ret = random.sample(new_num_l,4)
print(''.join(ret_l))



#高級方法:
def myrandom():
    new_num_l = list(map(str,range(10)))
    alph_l = [chr(i) for i in range(65,91)]  #列表推導式
    Alph_l = [chr(i) for i in range(97,124)]
    new_num_l.extend(alph_l)
    new_num_l.extend(Alph_l)
    ret_l = [random.choice(new_num_l) for i in range(4)]
    return ''.join(ret_l)
print(myrandom())
View Code

 

os模塊

 os模塊是與操作系統交互的一個接口

os.getcwd() 獲取當前工作目錄,即當前python腳本工作的目錄路徑
os.chdir("dirname")  改變當前腳本工作目錄;相當於shell下cd
os.curdir  返回當前目錄: ('.')
os.pardir  獲取當前目錄的父目錄字符串名:('..')
os.makedirs('dirname1/dirname2')    可生成多層遞歸目錄
os.removedirs('dirname1')    若目錄為空,則刪除,並遞歸到上一級目錄,如若也為空,則刪除,依此類推
os.mkdir('dirname')    生成單級目錄;相當於shell中mkdir dirname
os.rmdir('dirname')    刪除單級空目錄,若目錄不為空則無法刪除,報錯;相當於shell中rmdir dirname
os.listdir('dirname')    列出指定目錄下的所有文件和子目錄,包括隱藏文件,並以列表方式打印
os.remove()  刪除一個文件
os.rename("oldname","newname")  重命名文件/目錄
os.stat('path/filename')  獲取文件/目錄信息
os.sep    輸出操作系統特定的路徑分隔符,win下為"\\",Linux下為"/"
os.linesep    輸出當前平台使用的行終止符,win下為"\t\n",Linux下為"\n"
os.pathsep    輸出用於分割文件路徑的字符串 win下為;,Linux下為:
os.name    輸出字符串指示當前使用平台。win->'nt'; Linux->'posix'
os.system("bash command")  運行shell命令,直接顯示
os.environ  獲取系統環境變量
os.path.abspath(path)  返回path規范化的絕對路徑
os.path.split(path)  將path分割成目錄和文件名二元組返回
os.path.dirname(path)  返回path的目錄。其實就是os.path.split(path)的第一個元素
os.path.basename(path)  返回path最后的文件名。如何path以/或\結尾,那么就會返回空值。即os.path.split(path)的第二個元素
os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path)  如果path是絕對路徑,返回True
os.path.isfile(path)  如果path是一個存在的文件,返回True。否則返回False
os.path.isdir(path)  如果path是一個存在的目錄,則返回True。否則返回False
os.path.join(path1[, path2[, ...]])  將多個路徑組合后返回,第一個絕對路徑之前的參數將被忽略
os.path.getatime(path)  返回path所指向的文件或者目錄的最后存取時間
os.path.getmtime(path)  返回path所指向的文件或者目錄的最后修改時間
os.path.getsize(path) 返回path的大小
所有關於os模塊的方法
在Linux和Mac平台上,該函數會原樣返回path,在windows平台上會將路徑中所有字符轉換為小寫,並將所有斜杠轉換為飯斜杠。
>>> os.path.normcase('c:/windows\\system32\\')   
'c:\\windows\\system32\\'   
   

規范化路徑,如..和/
>>> os.path.normpath('c://windows\\System32\\../Temp/')   
'c:\\windows\\Temp'   

>>> a='/Users/jieli/test1/\\\a1/\\\\aa.py/../..'
>>> print(os.path.normpath(a))
/Users/jieli/test1
os路徑處理
#方式一:推薦使用
import os
#具體應用
import os,sys
possible_topdir = os.path.normpath(os.path.join(
    os.path.abspath(__file__),
    os.pardir, #上一級
    os.pardir,
    os.pardir
))
sys.path.insert(0,possible_topdir)


#方式二:不推薦使用
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

 

 

 

sys模塊

sys模塊是與python解釋器交互的一個接口

sys.argv          # 命令行參數List,第一個元素是程序本身路徑
sys.exit(n)       # 退出程序,正常退出時exit(0)
sys.version       # 獲取Python解釋程序的版本信息
sys.maxint        # 最大的Int值
sys.path          # 返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值
sys.platform      # 返回操作系統平台名稱

 

序列化模塊

將原本的字典、列表等內容轉換成一個字符串的過程就叫做序列化

 

  • 字符串str——通過反序列化——數據結構
  • 數據結構——通過序列化——字符串str

 

比如,我們在python代碼中計算的一個數據需要給另外一段程序使用,那我們怎么給?
現在我們能想到的方法就是存在文件里,然后另一個python程序再從文件里讀出來。
但是我們都知道,對於文件來說是沒有字典這個概念的,所以我們只能將數據轉換成字典放到文件中。
你一定會問,將字典轉換成一個字符串很簡單,就是str(dic)就可以辦到了,為什么我們還要學習序列化模塊呢?
沒錯序列化的過程就是從dic 變成str(dic)的過程。現在你可以通過str(dic),將一個名為dic的字典轉換成一個字符串,
但是你要怎么把一個字符串轉換成字典呢?
聰明的你肯定想到了eval(),如果我們將一個字符串類型的字典str_dic傳給eval,就會得到一個返回的字典類型了。
eval()函數十分強大,但是eval是做什么的?e官方demo解釋為:將字符串str當成有效的表達式來求值並返回計算結果。
BUT!強大的函數有代價。安全性是其最大的缺點。
想象一下,如果我們從文件中讀出的不是一個數據結構,而是一句"刪除文件"類似的破壞性語句,那么后果實在不堪設設想。
而使用eval就要擔這個風險。
所以,我們並不推薦用eval方法來進行反序列化操作(將str轉換成python中的數據結構)
注意事項

序列化的目的

1、以某種存儲形式使自定義對象持久化;
2、將對象從一個地方傳遞到另一個地方。
3、使程序更具維護性。

Json模塊是序列化模塊的一種,提供了四個功能:dumps、dump、loads、load,下面是具體功能:

#dumps和loads的用法
import json
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = json.dumps(dic)  #序列化:將一個字典轉換成一個字符串
print(type(str_dic),str_dic)  #<class 'str'> {"k3": "v3", "k1": "v1", "k2": "v2"}
#注意,json轉換完的字符串類型的字典中的字符串是由""表示的

dic2 = json.loads(str_dic)  #反序列化:將一個字符串格式的字典轉換成一個字典
#注意,要用json的loads功能處理的字符串類型的字典中的字符串必須由""表示
print(type(dic2),dic2)  #<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}


list_dic = [1,['a','b','c'],3,{'k1':'v1','k2':'v2'}]
str_dic = json.dumps(list_dic) #也可以處理嵌套的數據類型 
print(type(str_dic),str_dic) #<class 'str'> [1, ["a", "b", "c"], 3, {"k1": "v1", "k2": "v2"}]
list_dic2 = json.loads(str_dic)
print(type(list_dic2),list_dic2) #<class 'list'> [1, ['a', 'b', 'c'], 3, {'k1': 'v1', 'k2': 'v2'}]



#dump和load的用法
import json
f = open('json_file','w')
dic = {'k1':'v1','k2':'v2','k3':'v3'}
json.dump(dic,f)  #dump方法接收一個文件句柄,直接將字典轉換成json字符串寫入文件
f.close()

f = open('json_file')
dic2 = json.load(f)  #load方法接收一個文件句柄,直接將文件中的json字符串轉換成數據結構返回
f.close()
print(type(dic2),dic2)
View Code

 

pickle模塊也是序列化的一種,它與json極其相似,甚至說比json還要厲害。

    json是用於字符串 和 python數據類型間進行轉換,pickle是用於python特有的類型 和 python的數據類型間進行轉換

    pickle模塊提供了四個功能:dumps、dump(序列化,存)、loads(反序列化,讀)、load  (不僅可以序列化字典,列表...         還可以把python中任意的數據類型序列化

注:這里我們要說明一下,json是一種所有的語言都可以識別的數據結構。如果我們將一個字典或者列表序列化成了一個json存在文件里,那么java代碼或者js代碼也可以拿來用。但是如果我們用pickle進行序列化,其他語言就不能讀懂這是什么了。所以,如果你序列化的內容是列表或者字典,非常推薦使用json模塊。但如果出於某種原因你不得不序列化其他的數據類型,而未來還會用python對這個數據進行反序列化的話,那么就可以使用pickle。

這里對pickle模塊的用法進行說明:

import pickle
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = pickle.dumps(dic)
print(str_dic)  #一串二進制內容

dic2 = pickle.loads(str_dic)
print(dic2)    #字典

import time
struct_time  = time.localtime(1000000000)
print(struct_time)
f = open('pickle_file','wb')
pickle.dump(struct_time,f)
f.close()

f = open('pickle_file','rb')
struct_time2 = pickle.load(f)
print(struct_time.tm_year)

 

shelve模塊

shelve也是python提供給我們的序列化工具,比pickle用起來更簡單一些。shelve只提供給我們一個open方法,是用key來訪問的,使用起來和字典類似。

import shelve
f = shelve.open('shelve_file')
f['key'] = {'int':10, 'float':9.5, 'string':'Sample data'}  #直接對文件句柄操作,就可以存入數據
f.close()

import shelve
f1 = shelve.open('shelve_file')
existing = f1['key']  #取出數據的時候也只需要直接用key獲取即可,但是如果key不存在會報錯
f1.close()
print(existing)

 

這個模塊有個限制,它不支持多個應用同一時間往同一個DB進行寫操作。所以當我們知道我們的應用如果只進行讀操作,我們可以讓shelve通過只讀方式打開DB

import shelve
f = shelve.open('shelve_file', flag='r')
existing = f['key']
f.close()
print(existing)

 

由於shelve在默認情況下是不會記錄待持久化對象的任何修改的,所以我們在shelve.open()時候需要修改默認參數,否則對象的修改不會保存。

import shelve
f1 = shelve.open('shelve_file')
print(f1['key'])
f1['key']['new_value'] = 'this was not here before'
f1.close()

f2 = shelve.open('shelve_file', writeback=True)
print(f2['key'])
f2['key']['new_value'] = 'this was not here before'
f2.close()

writeback方式有優點也有缺點。優點是減少了我們出錯的概率,並且讓對象的持久化對用戶更加的透明了;但這種方式並不是所有的情況下都需要,首先,使用writeback以后,shelf在open()的時候會增加額外的內存消耗,並且當DB在close()的時候會將緩存中的每一個對象都寫入到DB,這也會帶來額外的等待時間。因為shelve沒有辦法知道緩存中哪些對象修改了,哪些對象沒有修改,因此所有的對象都會被寫入。

 

 

 hashlib模塊

  hashlib模塊的功能是提供了常見的摘要算法,如MD5,SHA1,SHA256,SHA512等等

  那么,什么是摘要算法呢?摘要算法就是可以把任意長度的數據轉換為固定長度的字符串(通常用16進制的字符串表示)。摘要算法就是通過摘要函數f()對任意長度的數據data計算出固定長度的摘要digest,目的是為了發現原始數據是否被人篡改過,也可以用來加密文件。

  摘要算法之所以能指出數據是否被篡改過,就是因為摘要函數是一個單向函數,計算f(data)很容易,但通過digest反推data卻非常困難。而且,對原始數據做一個bit的修改,都會導致計算出的摘要完全不同。

這里以常見的摘要算法MD5為例,計算出一個字符串的MD5值:

import hashlib
 
obj = hashlib.md5()
obj.update('what is your name?')
print md5.hexdigest()

計算結果如下:
d26a53750bc40b38b65a520292f69306


#如果數據量很大,可以分塊多次調用update(),最后計算的結果是一樣的:
obj= hashlib.md5()
obj.update('hello,my name is jack')
obj.update('what is your name')
obj.update('nice to meet you')
obj.update('goodbye')
print md5.hexdigest()
#其結果與將所有的話合成一句話后調用摘要算法的結果完全一樣

 

MD5是最常見的摘要算法,速度很快,生成結果是固定的128 bit字節,通常用一個32位的16進制字符串表示。另一種常見的摘要算法是SHA1,調用SHA1和調用MD5完全類似:

import hashlib
 
sha1 = hashlib.sha1()
sha1.update('you motherfuker ')
sha1.update('oh shit,get out of here!')
print sha1.hexdigest()

 

摘要算法的一大應用就是將文件進行加密。

  任何允許用戶登錄的網站都會存儲用戶登錄的用戶名和口令。如何存儲用戶名和口令呢?方法是存到數據庫表中。如果以明文保存用戶口令,如果數據庫泄露,所有用戶的口令就落入黑客的手里。此外,網站運維人員是可以訪問數據庫的,也就是能獲取到所有用戶的口令。正確的保存口令的方式是不存儲用戶的明文口令,而是存儲用戶口令的摘要,比如MD5。

  但是如果你的口令設置的過於簡單比如‘123’,‘abc’之類的,攻擊者可以實現算出這些值的摘要,然后來進行比對,一旦有用戶的口令簡單到被黑客猜中了,就會收到攻擊。所以這就是為什么都推薦大家將密碼設置的相對復雜的原因,諸如123、888、生日之類的盡量避免。

  當然啦,為了保護這些腦回路簡單的用戶的安全,網站的程序員在編碼時也會對考慮到這些問題並采取相應的措施。一般是通過對原始口令加一個復雜字符串來實現,俗稱“加鹽”

import hashlib
 
sha1 = hashlib.sha1(‘i am the salt’)#在初始位置加個東西,每個人的口令都會加上這一串,從而起到復雜化的作用,俗稱‘加鹽’
sha1.update('you motherfuker ')
sha1.update('oh shit,get out of here!')
print sha1.hexdigest()

  經過加鹽處理的MD5口令,只要‘鹽’不被黑客知道,即使用戶輸入簡單口令,就很難通過MD5反推明文口令。

  但是如果有兩個用戶都使用了相同的簡單口令比如123456,在數據庫中,將存儲兩條相同的MD5值,這說明這兩個用戶的口令是一樣的。有沒有辦法讓使用相同口令的用戶存儲不同的MD5呢?如果假定用戶無法修改登錄名,就可以通過把登錄名作為Salt的一部分來計算MD5,從而實現相同口令的用戶也存儲不同的MD5。

 注:摘要算法不是加密算法,不能用於加密(因為無法通過摘要反推明文),只能用於防篡改,但是它的單向計算特性決定了可以在不存儲明文口令的情況下驗證用戶口令。

 

configparser模塊

該模塊適用於配置文件的格式與windows ini文件類似,可以包含一個或多個節(section),每個節可以有多個參數(鍵=值)。

來看一個好多軟件的常見文檔格式如下:

[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
  
[bitbucket.org]
User = hg
  
[topsecret.server.com]
Port = 50022
ForwardX11 = no

 

接下來我們用python生成一個這樣的文檔

import configparser

config = configparser.ConfigParser()

config["DEFAULT"] = {'ServerAliveInterval': '45',
                      'Compression': 'yes',
                     'CompressionLevel': '9',
                     'ForwardX11':'yes'
                     }

config['bitbucket.org'] = {'User':'hg'}

config['topsecret.server.com'] = {'Host Port':'50022','ForwardX11':'no'}

with open('example.ini', 'w') as configfile:

   config.write(configfile)

 

查找文件

import configparser

config = configparser.ConfigParser()

#---------------------------查找文件內容,基於字典的形式

print(config.sections())        #  []

config.read('example.ini')

print(config.sections())        #   ['bitbucket.org', 'topsecret.server.com']

print('bytebong.com' in config) # False
print('bitbucket.org' in config) # True


print(config['bitbucket.org']["user"])  # hg

print(config['DEFAULT']['Compression']) #yes

print(config['topsecret.server.com']['ForwardX11'])  #no


print(config['bitbucket.org'])          #<Section: bitbucket.org>

for key in config['bitbucket.org']:     # 注意,有default會默認default的鍵
    print(key)

print(config.options('bitbucket.org'))  # 同for循環,找到'bitbucket.org'下所有鍵

print(config.items('bitbucket.org'))    #找到'bitbucket.org'下所有鍵值對

print(config.get('bitbucket.org','compression')) # yes       get方法Section下的key對應的value

 

增刪改操作

import configparser

config = configparser.ConfigParser()

config.read('example.ini')

config.add_section('yuan')



config.remove_section('bitbucket.org')
config.remove_option('topsecret.server.com',"forwardx11")


config.set('topsecret.server.com','k1','11111')
config.set('yuan','k2','22222')

config.write(open('new2.ini', "w"))

 

 

 

      


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM