python之經常使用模塊

python之經常使用模塊

標籤(空格分隔): pythonpython


什麼是模塊?

  • 在計算機程序開發的過程當中,隨着程序代碼越寫越多,在一個文件裏代碼就會愈來愈長,愈來愈不容易維護,爲了編寫可維護的代碼,咱們把不少函數分組,分別放到不一樣的文件裏面,這樣每一個文件裏面包含的代碼就相對較少了,不少的編程語言都採用這種組織代碼的方式,在python中,一個.py文件就是一個模塊;

使用模塊的好處?

  • 1.最大的好處就是大大提升了代碼的可維護性,其次,編寫代碼沒必要從零開始,當一個模塊編寫完畢了,就能夠被其餘的模塊引用,咱們在編寫程序的時候,也常常引用其餘的模塊,包括python 內置模塊和來自第三方的模塊,
    2.使用模塊能夠避免函數名和變量的衝突,每一個模塊有獨立的命名空間,所以相同名字的函數和變量徹底能夠分別在不一樣的模塊中,因此,咱們本身在編寫模塊時,沒必要考慮名字會與其餘的模塊的衝突;

模塊分類

模塊分爲3類:
1.內置標準模塊,又稱爲:標準庫,執行(help'modules')查看全部的python自帶模塊列表;
2.第三方開源模塊,可經過pip install 模塊名,聯網安裝;
3.自定義模塊;linux

模塊的調用

import module
from module import xx
from module.xx.xx import xx as rename
from module.xx.xx import *
  • 注意:模塊一旦被調用,即至關於執行了另一個py文件裏面的代碼;

自定義模塊:

這個最簡單,建立一個.py文件,就能夠稱之爲模塊,就能夠在另外一個程序裏面導入了;git

開源模塊的學習安裝方式:

pip install xx

time 模塊詳解

本節重點:time and datetime 的使用

  • 在平時的代碼中,咱們經常使用須要和時間打交道,在Python中與時間打交道的就是:time,datetime,calendar(不多用)下面分別來介紹:

在python中一般有這幾種方式來表示時間:
1.時間戳
2.格式化時間字符串
3.元組(struct_time)共九個元素,因爲python的time模塊實現主要調用C庫,因此各個平臺可能有所不一樣;web

幾個定義:

1.UTC(Coordinated Universal Time,世界協調時)亦即格林威治天文時間,世界標準時間。在中國爲UTC+8。DST(Daylight Saving Time)即夏令時。算法

2.時間戳(timestamp)的方式:一般來講,時間戳表示的是從1970年1月1日00:00:00開始按秒計算的偏移量。咱們運行「type(time.time())」,返回的是float類型。shell

3.元組(struct_time)方式:struct_time元組共有9個元素,返回struct_time的函數主要有gmtime(),localtime(),strptime()。下面列出這種方式元組中的幾個元素:數據庫

2.png-21.7kB

time 模塊和方法:

  • time.localtime([secs]):將一個時間戳轉換爲當前時區的struct_time,secs參數未提供,則以當前時間爲準;
import time
print(time.localtime())

執行結果:time.struct_time(tm_year=2018, tm_mon=6, tm_mday=25, tm_hour=22, tm_min=13, tm_sec=35, tm_wday=0, tm_yday=176, tm_isdst=0)編程

a=time.localtime()
b='%s-%s-%s'%(a.tm_year,a.tm_mon,a.tm_mday)
print(b)

執行結果:
'2018-6-25'json

  • time.gmtime([secs]):和localtime()方法相似,gmtime()方法是將一個時間戳轉換爲UTC時區(0時區)的struct_time。
a=time.gmtime()
print(a)

執行結果:
time.struct_time(tm_year=2018, tm_mon=6, tm_mday=25, tm_hour=14, tm_min=19, tm_sec=40, tm_wday=0, tm_yday=176, tm_isdst=0)
方法不傳值,默認打印的是當前的時間;
以下的代碼c#

a=time.localtime(14700032232)
print(a)

執行結果:會有對應的時間打印出來

  • time.time():返回當前時間的時間戳
  • time.mktime():將一個struct_time轉化爲時間戳
  • time.sleep(secs):線程推遲指定的時間運行,單位爲秒
  • tiem.asctime([t]):把一個時間的元組或者struct_time表示爲這種形式:sun oct 1 12:04:38 2017,若是沒有參數,將會將time.localtime()做爲參數傳入;
  • time.ctime([secs]):把一個時間戳(秒)轉化爲time.asctime()的形式,若是參數未給,或者爲None的時候,將會默認time.time()做爲參數,他的做用至關於time.asctime(time.localtime(secs))
  • time.strftime(format[,t]):把一個表明時間的元組或者struct_time(如由time.localtime()和time.gmtime()返回)轉化爲格式化的時間字符串,若是t未指定,將會傳入,time.localtime()
time.strftime('2017-8')
time.strftime('%Y-%m-%d %H:%M:%S',)
time.strftime('%Y-%m-%d %H:%M:%S %p',)#上午下午
time.strftime('%Y-%m-%d %H:%M:%S %U',)#這個一年的多少周
time.strftime('%Y-%m-%d %H:%M:%S %w',)#這個是周幾

3.png-34.1kB

datetime模塊

相對於time模塊,datetime模塊的接口直觀,更加容易調用;
datetime模塊定義了以下的幾個類:

  • datetime.date:表示日期的類,經常使用的屬性有:year month,day
  • datetime.time:表示時間的類,經常使用的屬性有:hour,minute,second,microsecond
  • datetime.datetime :表示日期時間
  • datetime.timedelta:表示時間間隔,即兩個時間點之間的長度
  • datetime.tzinfo 與時區有關的相關信息,(這裏再也不贅述,有興趣的同窗自行查看)
咱們須要記住的:

1.d=datetime.datetime.now()返回當前的datetime日期類型

import datetime
d=datetime.datetime。now()
print(d)
print(d.year)
print(d.today())
print(d.timestamp())
print(d.timetuple())

等方法能夠調用
2.datetime.formtimestamp(322222)把一個時間戳轉換爲datetime 日期類型;

datetime.date.fromtimestamp(time.time())

3.時間運算:

datetime.datetime.now()+datetime.timedelta(4)#當前時間+4天
datetime.datetime.now()+datetimetimedelta(hours=4)#當前時間+4小時

4.時間的替換

d=datetime.datetime.now()
d.replace(year=2999,month=11,day=30)
datetime.date(2999,11,30)

random 隨機數

程序中有不少的地方須要用到隨機字符,好比登陸網站的驗證碼,經過random模塊能夠很容易的生成隨機字符串

random.randrange(1,10)#返回1-10之間的一個隨機數,不包括10
random.randint(1,10)#返回1-10之間的一個隨機數,包括10
random.randrange(0,100,2)#隨機取0到100之間的偶數
random.random()#返回一個隨機浮點數
random.choice('abc#$@1')#返回一個給定數據集合中的隨機字符
random.sample('abcdefghij',3)#從多個字符串中選取特定數量的字符
#生成隨機的字符串
import string
''.json(random.sample(string.ascii_lowercase+string.digits,6))
#洗牌
a=[0,1,2,3,4,5,6,7,8,9]
random.shuffle(a)
print(a)

os模塊

1.獲得當前的工做路徑,即當前python腳本工做的路徑:os.getcwd(),注意這裏是python解釋器的路徑,不是你.py文件的路徑

import os
print(os.getcwd())

2.返回指定目錄下的全部文件和目錄名:os.listdir()

#返回當前目錄下的全部文件和目錄名
print(os.listdir('.'))

3.函數用來刪除一個文件:os.remove()

4.刪除多個目錄:os.removedirs()

os.removedirs(r"c:\python")

5.檢驗給出的路徑是否是一個文件:os.path.isfile()
返回值是true or false

6.檢驗給出的路徑是不是一個目錄:os.path.isdir()
返回值是true or false

7.判斷是不是絕對路徑:os.path.exists()
返回是true or false

8.返回一個路徑的目錄名和文件名:os.path.split()

os.path.split('/home/haha/lele/test.txt')

執行結果是:
('/home/haha/lele/','test.txt')
9.分離擴展名:os.path.splitext()

os.path.splittext('/home/haha/lele/test.txt')

執行結果:('/home/haha/lele/test','.py')
10.獲取路徑名字:os.path.dirname()
11.獲取絕對路徑:os.path.abspath()
12.獲取文件名:os.paht.basename()
13.運行shell命令:os.system()

os.system('df-h')#查看磁盤

14.讀取操做系統環境變量HOME的值:os.getenv('HOME')
15.返回操做系統全部的環境變量的值:os.environ
16.設置環境變量,僅僅程序運行的時候有效果:
os.environ.setdefault('HOME','/home/mimi')
17.給出當前平臺使用的終止符:os.linesep

  • windwos 使用的是:'\r\n',Linux使用的是:'\n',mac使用的是'\r'

18.指出你正在使用的平臺:os.name

  • windows 使用的是:'nt',而對於linux用戶,他是:'posix'

19.重命名:os.rename(old_name,new_name)
20.建立多級目錄:os.makedirs(r'c:\python\test')
21.建立單個目錄:os.mkdir('test')
22.獲取文件的屬性:os.stat(file)
23.終止當前進程:os.exit()
24.獲取文件的大小:os.path.getsize(filename)
25.修改文件的權限和時間戳:os.chmod(file)
26.結合目錄和文件名:os.path.join(dir,filename)
27.改變工做目錄到dirname:os.chdir(dirname)
28.獲取當前終端的大小:os.get_terminal_size()
29.殺死進程:os.kill(10884,signal.SIGKILL)

sys模塊的使用

1.sys.argv

python3 test.py run web

執行結果:
['test.py','run','web']
這個意思就是有的腳本後邊能夠跟參數,若是跟run咱們就執行run,若是跟web 咱們就執行web
2.sys.exit(n)退出程序,正常退出
3.sys.version 獲取當前解釋器的版本
4.sys.maxint 最大的Int值
5.sys.path 返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值
6.sys.platform 返回操做平臺的名稱
7.sys.getrecursionlimit()獲取遞歸的最大層數
8.sys.setrecursionlimit(1200) 設置最大遞歸層數
9.sys.getdefaultencoding() 獲取解釋器默認編碼
10.sys.getfilesystemencoding 獲取內存數據存到文件裏的默認編碼

shutil模塊

高級的文件,文件夾,壓縮包處理模塊

  • shutil.copyfileobj(fsrc,fdst[,llength])
    將文件內容拷貝到另外一個文件中,能夠部份內容
    源碼以下:
def copyfileobj(fsrc, fdst, length=16*1024):#這裏是每次讀多少,並非拷貝多少長度
    """copy data from file-like object fsrc to file-like object fdst"""
    while 1:
        buf = fsrc.read(length)#這裏是每次讀多少,並非拷貝多少長度
        if not buf:
            break
        fdst.write(buf)

演示:
新建一個文件叫sheve_test.py,內容以下圖所示並保存:
dfs.png-7.4kB

import shutil

f1=open("sheve_test.py",'r')
f2=open("sheve_test_new.py",'w')
shutil.copyfileobj(f1,f2)

而後新建一個.py文件用來編寫腳本,copy文件的

import shutil

f1=open("sheve_test.py",'r')
f2=open("sheve_test_new.py",'w')
shutil.copyfileobj(f1,f2)

如上述代碼執行完畢後,會生成一個文件:sheve_test_new.py文件,在這個文件裏面,會有和sheve_test.py文件同樣的內容;如上圖文件;

  • shutil.copyfile(src, dst)
    拷貝文件

源碼以下:

def copyfile(src, dst):
    """Copy data from src to dst"""
    if _samefile(src, dst):
        raise Error("`%s` and `%s` are the same file" % (src, dst))

    for fn in [src, dst]:
        try:
            st = os.stat(fn)
        except OSError:
            # File most likely does not exist
            pass
        else:
            # XXX What about other special files? (sockets, devices...)
            if stat.S_ISFIFO(st.st_mode):
                raise SpecialFileError("`%s` is a named pipe" % fn)

    with open(src, 'rb') as fsrc:
        with open(dst, 'wb') as fdst:
            copyfileobj(fsrc, fdst)
  • shutil.copymode(src, dst)
    僅拷貝權限。內容、組、用戶均不變

源碼以下:

def copymode(src, dst):
    """Copy mode bits from src to dst"""
    if hasattr(os, 'chmod'):
        st = os.stat(src)
        mode = stat.S_IMODE(st.st_mode)
        os.chmod(dst, mode)
  • shutil.copystat(src, dst)
    拷貝狀態的信息,包括:mode bits, atime, mtime, flags

源碼以下:

def copystat(src, dst):
    """Copy all stat info (mode bits, atime, mtime, flags) from src to dst"""
    st = os.stat(src)
    mode = stat.S_IMODE(st.st_mode)
    if hasattr(os, 'utime'):
        os.utime(dst, (st.st_atime, st.st_mtime))
    if hasattr(os, 'chmod'):
        os.chmod(dst, mode)
    if hasattr(os, 'chflags') and hasattr(st, 'st_flags'):
        try:
            os.chflags(dst, st.st_flags)
        except OSError, why:
            for err in 'EOPNOTSUPP', 'ENOTSUP':
                if hasattr(errno, err) and why.errno == getattr(errno, err):
                    break
            else:
                raise
  • shutil.copy(src, dst)
    拷貝文件和權限

源碼以下:

def copy(src, dst):
    """Copy data and mode bits ("cp src dst").

    The destination may be a directory.

    """
    if os.path.isdir(dst):
        dst = os.path.join(dst, os.path.basename(src))
    copyfile(src, dst)
    copymode(src, dst
  • shutil.copy2(src, dst)
    拷貝文件和狀態信息

源碼以下:

def copy2(src, dst):
    """Copy data and all stat info ("cp -p src dst").

    The destination may be a directory.

    """
    if os.path.isdir(dst):
        dst = os.path.join(dst, os.path.basename(src))
    copyfile(src, dst)
    copystat(src, dst)
  • shutil.ignore_patterns(*patterns)
    shutil.copytree(src, dst, symlinks=False, ignore=None)
    遞歸的去拷貝文件

例如:copytree(source, destination, ignore=ignore_patterns('.pyc', 'tmp'))

  • shutil.rmtree(path[, ignore_errors[, onerror]])
    遞歸的去刪除文件
  • shutil.move(src, dst)
    遞歸的去移動文件

序列化模塊:

什麼是序列化?

序列化,是指吧內存裏的數據類型轉化成爲字符串,以使其能存儲到硬盤或者經過網絡傳輸到遠程,由於硬盤或者網絡傳輸之恩可以接受bytes

爲何要序列化?

你打遊戲的時候,打累了,休息了2天,關掉遊戲,結果你下次開始仍是從你上次的地方接着打,那麼你上次玩遊戲的進度確定是存在硬盤上了,是以何種形式呢?
遊戲過程當中產生的不少臨時數據是不規律的,可能在你關掉,遊戲的時候正好有10個列表,3個嵌套字典數據,集合在內存裏面,須要存下來,你如何存呢?把列表變成文件裏的多行多列的形式?那嵌套字典呢?根本沒辦法存,因此,如果有種辦法能夠直接把內存數據存到硬盤上,下次程序啓動,在從硬盤上讀回來,仍是原來的格式化,天然是極好的辦法;

  • 用於序列化的兩個模塊:
    json,用於字符串和python數據類型間進行轉換;
    pickle,用於python特有的類型和python的數據類型間進行轉換;
    jso.jpg-382.6kB
data = {'roles': [

    {'role': 'monster', 'type': 'pig', 'life': 50},
    {'role': 'hero', 'type': '關羽', 'life': 80},
]}

f = open("game_status", 'w')
f.write(data)

執行結果:
Traceback (most recent call last):
File "G:/fancy/misc/shuiltdemo.py", line 8, in
f.write(data)
TypeError: write() argument must be str, not dict

Process finished with exit code 1

報錯了,信息顯示必需要接收str類型;

data = {'roles': [

    {'role': 'monster', 'type': 'pig', 'life': 50},
    {'role': 'hero', 'type': '關羽', 'life': 80},
]}

f = open("game_status", 'w')
f.write(str(data))

執行以上結果就ok了不會報錯了;

  • 緊接着上述的步驟走:
    把建立的game_status文件的內容讀出來:
f = open("game_status",'r')
d=f.read()
print(d['roles'])

執行結果:
Traceback (most recent call last):
File "G:/fancy/misc/shuiltdemo.py", line 12, in
print(d['roles'])
TypeError: string indices must be integers

結果報錯,由於d是str類型的

這裏就須要咱們把str變爲字典,那咱們採起以下的手段:

d=dict(d)

執行結果:
d=dict(d)
ValueError: dictionary update sequence element #0 has length 1; 2 is required
結果仍是不行;

  • 如上的問題就是字典轉成字符串,在反轉就轉不會來了,這就是這個問題,那咱們怎麼辦呢?
  • 這裏咱們以前學過:eval()
f = open("game_status",'r')
d=f.read()
d=eval(d)
print(d['roles'])

執行結果爲:
[{'role': 'monster', 'type': 'pig', 'life': 50}, {'role': 'hero', 'type': '關羽', 'life': 80}]

  • 把內存數據轉成字符,叫作序列化
    把字符轉成內存數據,叫作反序列化;
    剛剛的代碼作了兩件事情:1.是把字典變成字符串,2.是把字符串eval()一下,轉換爲內存數據;
  • 其實在python裏面有自帶的模塊專門幹這個功能的;
    1.pickle 模塊
    2.json 模塊
    這兩個模塊的主要功能就是內存的數據很容易存下來,也很容易讀出來;
    這兩個模塊的用法徹底同樣;
  • json:
    1.dumps()
import json

data = {'roles': [

    {'role': 'monster', 'type': 'pig', 'life': 50},
    {'role': 'hero', 'type': '關羽', 'life': 80},
]}
d=json.dumps(data)#
print(d,type(d))

執行結果:
{"roles": [{"role": "monster", "type": "pig", "life": 50}, {"role": "hero", "type": "\u5173\u7fbd", "life": 80}]} <class 'str'>

如上結果能夠看出,他已是個字符串了;

2.dump()
這個和dumps()其實差很少,只是dumps()只傳入數據的參數,可是dump()要傳入數據和文件;

import json
data = {'roles': [
    {'role': 'monster', 'type': 'pig', 'life': 50},
    {'role': 'hero', 'type': '關羽', 'life': 80},
]}
json.dump(data,'test.json')#僅僅轉成字符串

執行結果:
AttributeError: 'str' object has no attribute 'write'
報錯了,

  • 這裏申明一下:dump()在傳入文件的時候,文件要是一個能夠寫的對象,由於他不能本身打開文件;
import json
data = {'roles': [
    {'role': 'monster', 'type': 'pig', 'life': 50},
    {'role': 'hero', 'type': '關羽', 'life': 80},
]}
f = open("test.json",'w')#增長些的權限,而且打開不文件
json.dump(data,f)#轉成字符串並寫入文件

如上述,執行結果不會報錯了,正常出現了test.json文件
jsn.png-25.5kB

  • loads()
import json
data = {'roles': [
    {'role': 'monster', 'type': 'pig', 'life': 50},
    {'role': 'hero', 'type': '關羽', 'life': 80},
]}
d=json.dumps(data)
d2=json.loads(d)
print(d2['roles'])

執行結果:
[{'role': 'monster', 'type': 'pig', 'life': 50}, {'role': 'hero', 'type': '關羽', 'life': 80}]

*load()
如下例子是打開剛剛生成的json文件

f =open('test.json','r')
    data=json.load(f)
    print(data)

執行結果爲:
{'roles': [{'role': 'monster', 'type': 'pig', 'life': 50}, {'role': 'hero', 'type': '關羽', 'life': 80}]}

1.把數據類型轉化爲字符串存到內存的意義?
json.dumps json.loads
a.把你的內存數據,經過網絡,共享給遠程其它人;
b.能夠跨平臺,跨語言共享你的數據;
c.定義了不一樣語言的以前的交互規則
純文本:壞處:不能共享給遠程其餘的人;
xml:壞處:佔用的空間大
json:簡單,可讀性好

  • 剛纔我只是把這個數據dumps()了一次,能不能dump()屢次呢?
    答案:
    是能夠的;這裏你們自行實驗;
    那能夠對於dump()屢次的,能夠load()嗎?,能夠load()屢次嗎

答案:
在load()的時候會報錯的,load()一次就會報錯,load()屢次也會報錯的;

  • 這裏注意,dump()了幾回,而後,load()第一次就會報錯,因此,咱們在使用dump()和load()的時候不要反覆的dump()和load()

總結:
json:的方法:
dumps()------------loads()
dump()--------------load()

pickle模塊

pickle和json的用法是一致的:
例子:以下代碼:

import pickle

d = {'name': 'alex', 'age': 22}
l = [1, 2, 3, 'rain']
pk = open('data.pkl','w')
print(pickle.dumps(d))

執行結果:
b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x04\x00\x00\x00alexq\x02X\x03\x00\x00\x00ageq\x03K\x
它會先轉化爲bytes類型;

import pickle

d = {'name': 'awaw', 'age': 22}
l = [1, 2, 3, 'rain']
pk = open('data.pkl', 'wb')
pickle.dump(d, pk)

pickle.png-11.2kB

那麼反序列化呢:

f=open('data.pkl','rb')
d=pickle.load(f)
print(d)

打開上圖的文件,而後進行load()就能夠了
執行結果爲:
{'name': 'awaw', 'age': 22}

  • json 和pickle的區別呢?
    json:支持:str int,tuple,list,dict,不支持set
    pickle:支持:python裏面的全部的數據類型,包括函數;
    2.這樣說來,pickle更牛逼,咱們之後就用pickle好了;
    答案不行:
    pickle之能在python裏面用,不能跨平臺,跨語言;(因此說沒用不用研究)

shelve模塊

以前說json和pickle只能dump,load一次,假如我確實有好幾種數據須要序列化,若是隻能dump一次的話,這就意味着我本身要dump好幾個文件,這個時候就感受很low,難道沒有辦法容許我dump好幾回嗎?
shelve他是對pickle的封裝,容許你dump屢次,load屢次,而且不會順序亂,由於他是一種key-value的形式;(這個下去本身研究,這裏不在多說了,由於它主要是對pickle封裝的)

configparser 模塊

不少軟件都有配置文件,來配置一些參數;
編寫一個配置文件叫:conf.ini
內容以下:

[DEFAULT]
ServerAliveInterval =45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[bitbucket.org]
User = hg

[topsecret.server.com]
Port=50022
ForwardX11 = no

而後進行以下的操做:

import configparser
conf=configparser.ConfigParser()
# print(conf.sections())
conf.read('conf.ini')
print(conf.default_section)#打印配置文件的deaulf
print(dir(conf["bitbucket.org"]))#打印bitbucket.org的值

for k,v in conf["bitbucket.org"].items():
    print(k,v)#這時候default的內容也會展現出來,默認default會在後續的節點都會展現出來

增刪改查,本身行研究;

hashlib模塊:

在講解這個模塊以前先給你們說一些,關於加密的一些知識:
HASH

  • Hash,通常翻譯作「散列」,也有直接音譯爲」哈希」的,就是把任意長度的輸入(又叫作預映射,pre-image),經過散列算法,變換成固定長度的輸出,該輸出就是散列值。這種轉換是一種壓縮映射,也就是,散列值的空間一般遠小於輸入的空間,不一樣的輸入可能會散列成相同的輸出,而不可能從散列值來惟一的肯定輸入值。
  • 簡單的說就是一種將任意長度的消息壓縮到某一固定長度的消息摘要的函數。
  • HASH主要用於信息安全領域中加密算法,他把一些不一樣長度的信息轉化成雜亂的128位的編碼裏,叫作HASH值.也能夠說,hash就是找到一種數據內容和數據存放地址之間的映射關係

MD5

  • 輸入任意長度的信息,通過處理,輸出爲128位的信息(數字指紋);不一樣的輸入獲得的不一樣的結果(惟一性);
  • MD5算法的特色
    1.壓縮性:任意長度的數據,算出的MD5值的長度都是固定的
    2.容易計算:從原數據計算出MD5值很容易
    3.抗修改性:對原數據進行任何改動,修改一個字節生成的MD5值區別也會很大
    4.強抗碰撞:已知原數據和MD5,想找到一個具備相同MD5值的數據(即僞造數據)是很是困難的。

MD5算法是否可逆?

  • MD5不可逆的緣由是其是一種散列函數,使用的是hash算法,在計算過程當中原文的部分信息是丟失了的。

MD5用途

1.防止被篡改:
好比發送一個電子文檔,發送前,我先獲得MD5的輸出結果a。而後在對方收到電子文檔後,對方也獲得一個MD5的輸出結果b。若是a與b同樣就表明中途未被篡改。

好比我提供文件下載,爲了防止不法分子在安裝程序中添加木馬,我能夠在網站上公佈由安裝文件獲得的MD5輸出結果。

SVN在檢測文件是否在CheckOut後被修改過,也是用到了MD5.

2.防止直接看到明文:
如今不少網站在數據庫存儲用戶的密碼的時候都是存儲用戶密碼的MD5值。這樣就算不法分子獲得數據庫的用戶密碼的MD5值,也沒法知道用戶的密碼。(好比在UNIX系統中用戶的密碼就是以MD5(或其它相似的算法)經加密後存儲在文件系統中。當用戶登陸的時候,系統把用戶輸入的密碼計算成MD5值,而後再去和保存在文件系統中的MD5值進行比較,進而肯定輸入的密碼是否正確。經過這樣的步驟,系統在並不知道用戶密碼的明碼的狀況下就能夠肯定用戶登陸系統的合法性。這不但能夠避免用戶的密碼被具備系統管理員權限的用戶知道,並且還在必定程度上增長了密碼被破解的難度。)

3.防止抵賴:(數字簽名)
這須要一個第三方認證機構。例如A寫了一個文件,認證機構對此文件用MD5算法產生摘要信息並作好記錄。若之後A說這文件不是他寫的,權威機構只需對此文件從新產生摘要信息,而後跟記錄在冊的摘要信息進行比對,相同的話,就證實是A寫的了。這就是所謂的「數字簽名」。

SHA-1

安全哈希算法(Secure Hash Algorithm)主要適用於數字簽名標準(Digital Signature Standard DSS)裏面定義的數字簽名算法(Digital Signature Algorithm DSA)。對於長度小於2^64位的消息,SHA1會產生一個160位的消息摘要。當接收到消息的時候,這個消息摘要能夠用來驗證數據的完整性。

SHA是美國國家安全局設計的,由美國國家標準和技術研究院發佈的一系列密碼散列函數。

因爲MD5和SHA-1於2005年被山東大學的教授王小云破解了,科學家們又推出了SHA224, SHA256, SHA384, SHA512,固然位數越長,破解難度越大,但同時生成加密的消息摘要所耗時間也更長。目前最流行的是加密算法是SHA-256 .

MD5與SHA-1的比較

因爲MD5與SHA-1均是從MD4發展而來,它們的結構和強度等特性有不少類似之處,SHA-1與MD5的最大區別在於其摘要比MD5摘要長32 比特。對於強行攻擊,產生任何一個報文使之摘要等於給定報文摘要的難度:MD5是2128數量級的操做,SHA-1是2160數量級的操做。產生具備相同摘要的兩個報文的難度:MD5是264是數量級的操做,SHA-1 是280數量級的操做。於是,SHA-1對強行攻擊的強度更大。但因爲SHA-1的循環步驟比MD5多80:64且要處理的緩存大160比特:128比特,SHA-1的運行速度比MD5慢.

Python的 提供的相關模塊:

用於加密相關的操做,3.x裏代替了md5模塊和sha模塊,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法

import hashlib

m = hashlib.md5()
m.update(b"Hello")
m.update(b"It's me")
print(m.digest())
m.update(b"It's been a long time since last time we ...")

print(m.digest()) #2進制格式hash
print(len(m.hexdigest())) #16進制格式hash
'''
def digest(self, *args, **kwargs): # real signature unknown
    """ Return the digest value as a string of binary data. """
    pass

def hexdigest(self, *args, **kwargs): # real signature unknown
    """ Return the digest value as a string of hexadecimal digits. """
    pass

'''
import hashlib

# ######## md5 ########

hash = hashlib.md5()
hash.update('admin')
print(hash.hexdigest())

# ######## sha1 ########

hash = hashlib.sha1()
hash.update('admin')
print(hash.hexdigest())

# ######## sha256 ########

hash = hashlib.sha256()
hash.update('admin')
print(hash.hexdigest())


# ######## sha384 ########

hash = hashlib.sha384()
hash.update('admin')
print(hash.hexdigest())

# ######## sha512 ########

hash = hashlib.sha512()
hash.update('admin')
print(hash.hexdigest())

例如以下例子:

import hashlib
print(hash('wang'))

執行結果爲:
3991323452314028184

  • 注意只要程序不退出,wang的全部的hash都是這個字符串,一旦退出從新進入程序,從新編譯,就不是這樣的結果了;
  • hash 是不可逆的,即便知道了:3991323452314028184也不能反推出來:wang
    因此常被用於各個的加密網站,是加密的基礎的東西;

subrpocess模塊

  • 咱們常常須要經過Python去執行一條系統命令或腳本,系統的shell命令是獨立於你的python進程以外的,每執行一條命令,就是發起一個新進程,經過python調用系統命令或腳本的模塊在python2有os.system
import os
os.system('uname')

執行結果(小編是Mac):
Darwin
0
這個代碼就是執行系統的命令,其中0就是執行的狀態,每一個系統都是有狀態,Linux就是成功:0,若是是非零就是說明失敗;
linux中經過:echo $?能夠查看上一個命令執行的一個狀態;

import os
a=os.sytem('df')
print(a)# a=0這裏a是上次執行的一個狀態;

經過上述的代碼我是拿不到os.system('df')輸出 的結果的,若是我想拿到怎麼辦呢?
os.popen('df -h')
執行結果:<os._wrap_close object at 0x103a14588>
至關於在內存裏面打開了一個臨時文件,把內容存到臨時文件裏面;so,咱們只須要把這個文件讀出來就行了;

import os
os.system('df')
f=os.popen('df -h')
f.read()

so:咱們須要學習subprocess
以前調用操做系統,執行命令的方法不少種,python2也有不少種,例如:commands,python3清理一些不規範的東西,把以前的東西規範化,subsprocess替換了別的,規範化;

  • 三種執行命令的方法:
1.subprocess.run(*popenargs, input=None, timeout=None, check=False, **kwargs) #官方推薦
2. subprocess.call(*popenargs, timeout=None, **kwargs) #跟上面實現的內容差很少,另外一種寫法
3.subprocess.Popen() #上面各類方法的底層封裝

run()方法:

  • 執行這個命令,返回一個對象,拿着對象執行命令;
    1.標準寫法:
    subprocess.run(['df','-h'],stderr=subprocess.PIPE,stdout=subprocess.PIPE,check=True)
    2.涉及到管道|的命令須要這樣寫
    subprocess.run('df -h|grep disk1',shell=True) #shell=True的意思是這條命令直接交給系統去執行,不須要python負責解析

call()方法:

#執行命令,返回命令執行狀態 , 0 or 非0
>>> retcode = subprocess.call(["ls", "-l"])
#執行命令,若是命令結果爲0,就正常返回,不然拋異常
>>> subprocess.check_call(["ls", "-l"])
0
#接收字符串格式命令,返回元組形式,第1個元素是執行狀態,第2個是命令結果 
>>> subprocess.getstatusoutput('ls /bin/ls')
(0, '/bin/ls')
#接收字符串格式命令,並返回結果
>>> subprocess.getoutput('ls /bin/ls')
'/bin/ls'
#執行命令,並返回結果,注意是返回結果,不是打印,下例結果返回給res
>>> res=subprocess.check_output(['ls','-l'])
>>> res
b'total 0\ndrwxr-xr-x 12 alex staff 408 Nov 2 11:05 OldBoyCRM\n'

Popen()方法:

經常使用參數:

  • args:shell命令,能夠是字符串或者序列類型(如:list,元組)
    stdin, stdout, stderr:分別表示程序的標準輸入、輸出、錯誤句柄
    preexec_fn:只在Unix平臺下有效,用於指定一個可執行對象(callable object),它將在子進程運行以前被調用
    shell:同上
    cwd:用於設置子進程的當前目錄
    env:用於指定子進程的環境變量。若是env = None,子進程的環境變量將從父進程中繼承。
    下面這2條語句執行會有什麼區別?
    a=subprocess.run('sleep 10',shell=True,stdout=subprocess.PIPE)
    a=subprocess.Popen('sleep 10',shell=True,stdout=subprocess.PIPE)
    區別是Popen會在發起命令後馬上返回,而不等命令執行結果。這樣的好處是什麼呢?
    若是你調用的命令或腳本 須要執行10分鐘,你的主程序不需卡在這裏等10分鐘,能夠繼續往下走,幹別的事情,每過一會,經過一個什麼方法來檢測一下命令是否執行完成就行了。
    Popen調用後會返回一個對象,能夠經過這個對象拿到命令執行結果或狀態等,該對象有如下方法
    poll()
    Check if child process has terminated. Returns returncode
    wait()
    Wait for child process to terminate. Returns returncode attribute.
    terminate()終止所啓動的進程Terminate the process with SIGTERM
    kill() 殺死所啓動的進程 Kill the process with SIGKILL
    communicate()與啓動的進程交互,發送數據到stdin,並從stdout接收輸出,而後等待任務結束

    a = subprocess.Popen('python3 guess_age.py',stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE,shell=True)
    a.communicate(b'22')
    (b'your guess:try bigger\n', b'')
    send_signal(signal.xxx)發送系統信號
    pid 拿到所啓動進程的進程號

logging模塊:

logging模塊就是爲了幫助咱們記錄日誌,記錄日誌,爲了之後分析所用,或者除了問題能夠查看;

  • python的logging模塊提供了標準的日誌接口,你能夠經過它存儲各類格式的日誌,logging的日誌能夠分爲: debug(),info(), warning(),error()
    and critical()5個級別,下面咱們看一下怎麼用?

最簡單的用法:

import logging
logging.warning('i am logging 3 times')
logging.critical('server down')

執行結果:是輸出到屏幕的
WARNING:root:i am logging 3 times
CRITICAL:root:server down

  • 看一下日誌級別:
    log.png-63kB

若是要把日誌寫到文件裏呢?其實也簡單:

import logging
logging.basicConfig(filename='example.log',level=logging.INFO)
logging.debug('This message shouldn't go to the log file')
logging.info('So should this')
logging.warning('And this, too')

其中下面這句中的level=loggin.INFO意思是,把日誌紀錄級別設置爲INFO,也就是說,只有比日誌是INFO或比INFO級別更高的日誌纔會被紀錄到文件裏,在這個例子, 第一條日誌是不會被紀錄的,若是但願紀錄debug的日誌,那把日誌級別改爲DEBUG就好了

自定義日誌格式,加入時間:

import logging
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
logging.warning('is when this event was logged.')

#輸出
12/12/2010 11:46:36 AM is when this event was logged.

除了加時間,還能夠自定義一大堆格式,下表就是全部支持的格式:
log.png-103.8kB

logging模塊的高級階段:

  • 若是一條日誌同時向屏幕和文件打印怎麼辦?
    這裏咱們須要瞭解logging模塊的複雜知識:
    logging有4個主要的類:
    1.logger:提供了應用程序直接使用的接口;
    2.handler:將logger建立的日誌發送到合適的目的地:
    3.filter:提供過濾,來決定哪些日誌須要輸出;
    4.formatter決定日誌記錄的最終輸出格式;

他們之間的關係如圖:
8B2BFC9F-0689-4271-9723-C4136ED1C958.png-46kB

每一個組件的功能是:

logger

  • 每一個程序在輸出信息以前都要得到一個Logger。Logger一般對應了程序的模塊名,好比聊天工具的圖形界面模塊能夠這樣得到它的Logger:
LOG=loggin.getlogger('chat.gui')

而核心模塊能夠這樣設置:

LOG=logging.getlogger('chat.kernel')

還能夠綁定handler和filters:

  • Logger.setLevel(lel):指定最低的日誌級別,低於lel的級別將被忽略。debug是最低的內置級別,critical爲最高
    Logger.addFilter(filt)、Logger.removeFilter(filt):添加或刪除指定的filter
    Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增長或刪除指定的handler
    Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():能夠設置的日誌級別

handler

  • handler對象負責發送相關的信息到指定目的地。Python的日誌系統有多種Handler可使用。有些Handler能夠把信息輸出到控制檯,有些Handler能夠把信息輸出到文件,還有些 Handler能夠把信息發送到網絡上。若是以爲不夠用,還能夠編寫本身的Handler。能夠經過addHandler()方法添加多個多handler
  • Handler.setLevel(lel):指定被處理的信息級別,低於lel級別的信息將被忽略
    Handler.setFormatter():給這個handler選擇一個格式
    Handler.addFilter(filt)、Handler.removeFilter(filt):新增或刪除一個filter對象

每一個Logger能夠附加多個Handler。接下來咱們就來介紹一些經常使用的Handler:

  • 1.logging.StreamHandler 使用這個Handler能夠向相似與sys.stdout或者sys.stderr的任何文件對象(file object)輸出信息。
    2.logging.FileHandler 和StreamHandler 相似,用於向一個文件輸出日誌信息。不過FileHandler會幫你打開這個文件
    3.logging.handlers.RotatingFileHandler

這個Handler相似於上面的FileHandler,可是它能夠管理文件大小。當文件達到必定大小以後,它會自動將當前日誌文件更名,而後建立 一個新的同名日誌文件繼續輸出。好比日誌文件是chat.log。當chat.log達到指定的大小以後,RotatingFileHandler自動把 文件更名爲chat.log.1。不過,若是chat.log.1已經存在,會先把chat.log.1重命名爲chat.log.2。。。最後從新建立 chat.log,繼續輸出日誌信息。它的函數是:

  • RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
    其中filename和mode兩個參數和FileHandler同樣。
  • maxBytes用於指定日誌文件的最大文件大小。若是maxBytes爲0,意味着日誌文件能夠無限大,這時上面描述的重命名過程就不會發生。
  • backupCount用於指定保留的備份文件的個數。好比,若是指定爲2,當上面描述的重命名過程發生時,原有的chat.log.2並不會被改名,而是被刪除。

4.logging.handlers.TimedRotatingFileHandler
這個Handler和RotatingFileHandler相似,不過,它沒有經過判斷文件大小來決定什麼時候從新建立日誌文件,而是間隔必定時間就 自動建立新的日誌文件。重命名的過程與RotatingFileHandler相似,不過新的文件不是附加數字,而是當前時間。它的函數是:

  • TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])

其中filename參數和backupCount參數和RotatingFileHandler具備相同的意義。
interval是時間間隔。
when參數是一個字符串。表示時間間隔的單位,不區分大小寫。它有如下取值:

S 秒
M 分
H 小時
D 天
W 每星期(interval==0時表明星期一)
midnight 天天凌晨

formatter組件:

日誌的formatter是個獨立的組件,能夠跟handler組合

  • fh = logging.FileHandler("access.log")
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    fh.setFormatter(formatter) #把formmater綁定到fh上

filter 組件:過濾日誌:

class IgnoreBackupLogFilter(logging.Filter):
    """忽略帶db backup 的日誌"""
def filter(self, record): #固定寫法
    return   "db backup" not in record.getMessage()

filter 返回true或者false,logger 根據這個進行判斷是否輸出日誌;
例如:

import logging
#生成logger對象:
logger= logging.getLogger('web')
logger.setLevel(logging.INFO)
#生成hander對象
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
fh = logging.FileHandler('web.log')
fh.setLevel(logging.INFO)
#把handler對象綁定logger對象
logger.addHandler(ch)
logger.addHandler(fh)
#生成formatter對象
#把formatter對象綁定handler對象
file_format= logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
console_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(console_format)
fh.setFormatter(file_format)
logger.debug('test_log')
#console:DEBUG
#global:INFO(默認級別最高,若是不設置,就是說默認是Warning,就是說默認的就是Warning)
#file:Warning
  • 問題:如上述所示:全局級別的設置爲:INFO,屏幕的爲DEBUG,文件的爲INFO,這時候直接結果爲: 文件有內容,屏幕不輸出; 2.若是把全局設置爲DEBUG這時候看看:結果如何: 會發現,屏幕的輸出了,而文件的沒有輸出; 3.若是全局的不設置會怎樣,: 結果發現,屏幕和文件都沒有輸出,由於全局的若是不寫,默認是Warning,低於Warning都不會輸出;
相關文章
相關標籤/搜索