python序列化及加密算法的使用

一? 序列化模塊

什么叫序列化——將原本的字典绰筛、列表等內容轉換成一個字符串的過程就叫做序列化枢泰。

比如,我們在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寥枝、使程序更具維護性。


Python可序列化的數據類型:

| Python | JSON |

| dict? ? ? ? ? |? ? object? ? |

| list, tuple? |? ? array? ? |

| str? ? ? ? ? ? |? ? string? ? |

| int, float? ? |? ? number? |

| True? ? ? ? ? |? ? ? true? ? |

| False? ? ? ? ? |? ? ? false? ? |

| None? ? ? ? ? |? ? ? null? ? |

1.1 json模塊

Json模塊提供了四個功能:dumps磁奖、dump囊拜、loads、load

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'}]

loads和dumps

dumps loads

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)

其它參數說明:

Serialize obj to a JSON formatted str.(字符串表示的json對象)

Skipkeys:默認值是False蜜托,如果dict的keys內的數據不是python的基本類型(str,unicode,int,long,float,bool,None),設置為False時霉赡,就會報TypeError的錯誤橄务。此時設置成True,則會跳過這類key

ensure_ascii:穴亏,當它為True的時候蜂挪,所有非ASCII碼字符顯示為\uXXXX序列,只需在dump時將ensure_ascii設置為False即可迫肖,此時存入json的中文即可正常顯示锅劝。)

If check_circular is false, then the circular reference check for container types will be skipped and a circular reference will result in an OverflowError (or worse).

If allow_nan is false, then it will be a ValueError to serialize out of range float values (nan, inf, -inf) in strict compliance of the JSON specification, instead of using the JavaScript equivalents (NaN, Infinity, -Infinity).

indent:應該是一個非負的整型,如果是0就是頂格分行顯示蟆湖,如果為空就是一行最緊湊顯示故爵,否則會換行且按照indent的數值顯示前面的空白分行顯示,這樣打印出來的json數據也叫pretty-printed json

separators:分隔符隅津,實際上是(item_separator, dict_separator)的一個元組诬垂,默認的就是(‘,’,’:’);這表示dictionary內keys之間用“,”隔開伦仍,而KEY和value之間用“:”隔開结窘。

default(obj) is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError.

sort_keys:將數據根據keys的值進行排序。

To use a custom JSONEncoder subclass (e.g. one that overrides the .default() method to serialize additional types), specify it with the cls kwarg; otherwise JSONEncoder is used.

import json

data = {'username':['李華','二愣子'],'sex':'male','age':16}

json_dic2 = json.dumps(data,sort_keys=True,indent=2,separators=(',',':'),ensure_ascii=False)

print(json_dic2)

1.2 pickle模塊

用于序列化的兩個模塊

json充蓝,用于字符串 和 python數據類型間進行轉換

pickle隧枫,用于python特有的類型 和 python的數據類型間進行轉換

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

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_time2.tm_year)

這時候機智的你又要說了,既然pickle如此強大仑撞,為什么還要學json呢赤兴?

這里我們要說明一下妖滔,json是一種所有的語言都可以識別的數據結構。

如果我們將一個字典或者序列化成了一個json存在文件里桶良,那么java代碼或者js代碼也可以拿來用座舍。

但是如果我們用pickle進行序列化,其他語言就不能讀懂這是什么了~

所以艺普,如果你序列化的內容是列表或者字典簸州,我們非常推薦你使用json模塊

但如果出于某種原因你不得不序列化其他的數據類型,而未來你還會用python對這個數據進行反序列化的話歧譬,那么就可以使用pickle

二? hashlib模塊

算法介紹

Python的hashlib提供了常見的摘要算法岸浑,如MD5,SHA1等等瑰步。

什么是摘要算法呢矢洲?摘要算法又稱哈希算法、散列算法缩焦。它通過一個函數读虏,把任意長度的數據轉換為一個長度固定的數據串(通常用16進制的字符串表示)。

摘要算法就是通過摘要函數f()對任意長度的數據data計算出固定長度的摘要digest袁滥,目的是為了發(fā)現原始數據是否被人篡改過盖桥。

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

我們以常見的摘要算法MD5為例姜挺,計算出一個字符串的MD5值:

import hashlib

md5 = hashlib.md5()

md5.update('how to use md5 in python hashlib?')

print md5.hexdigest()

計算結果如下:

d26a53750bc40b38b65a520292f69306

如果數據量很大齿税,可以分塊多次調用update(),最后計算的結果是一樣的:

md5 = hashlib.md5()

md5.update('how to use md5 in ')

md5.update('python hashlib?')

print md5.hexdigest()

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

import hashlib

sha1 = hashlib.sha1()

sha1.update('how to use sha1 in ')

sha1.update('python hashlib?')

print sha1.hexdigest()

SHA1的結果是160 bit字節(jié),通常用一個40位的16進制字符串表示掖肋。比SHA1更安全的算法是SHA256和SHA512,不過越安全的算法越慢赏参,而且摘要長度更長志笼。

摘要算法應用

任何允許用戶登錄的網站都會存儲用戶登錄的用戶名和口令沿盅。如何存儲用戶名和口令呢?方法是存到數據庫表中:

name | password

--------+----------

michael | 123456

bob? ? | abc999

alice? | alice2008

如果以明文保存用戶口令纫溃,如果數據庫泄露腰涧,所有用戶的口令就落入黑客的手里。此外紊浩,網站運維人員是可以訪問數據庫的窖铡,也就是能獲取到所有用戶的口令。正確的保存口令的方式是不存儲用戶的明文口令坊谁,而是存儲用戶口令的摘要费彼,比如MD5:

username | password

---------+---------------------------------

michael? | e10adc3949ba59abbe56e057f20f883e

bob? ? ? | 878ef96e86145580c38c87f0410ad153

alice? ? | 99b1c2188db85afee403b1536010c2c9

考慮這么個情況,很多用戶喜歡用123456口芍,888888箍铲,password這些簡單的口令,于是鬓椭,黑客可以事先計算出這些常用口令的MD5值颠猴,得到一個反推表:

'e10adc3949ba59abbe56e057f20f883e': '123456'

'21218cca77804d2ba1922c33e0151105': '888888'

'5f4dcc3b5aa765d61d8327deb882cf99': 'password'

這樣,無需破解小染,只需要對比數據庫的MD5翘瓮,黑客就獲得了使用常用口令的用戶賬號。

對于用戶來講裤翩,當然不要使用過于簡單的口令资盅。但是,我們能否在程序設計上對簡單口令加強保護呢岛都?

由于常用口令的MD5值很容易被計算出來律姨,所以,要確保存儲的用戶口令不是那些已經被計算出來的常用口令的MD5臼疫,這一方法通過對原始口令加一個復雜字符串來實現择份,俗稱“加鹽”:

hashlib.md5("salt".encode("utf8"))

經過Salt處理的MD5口令,只要Salt不被黑客知道烫堤,即使用戶輸入簡單口令荣赶,也很難通過MD5反推明文口令。

但是如果有兩個用戶都使用了相同的簡單口令比如123456,在數據庫中,將存儲兩條相同的MD5值氮兵,這說明這兩個用戶的口令是一樣的把跨。有沒有辦法讓使用相同口令的用戶存儲不同的MD5呢?

如果假定用戶無法修改登錄名黎棠,就可以通過把登錄名作為Salt的一部分來計算MD5,從而實現相同口令的用戶也存儲不同的MD5哪廓。

摘要算法在很多地方都有廣泛的應用灭红。要注意摘要算法不是加密算法侣滩,不能用于加密(因為無法通過摘要反推明文),只能用于防篡改变擒,但是它的單向計算特性決定了可以在不存儲明文口令的情況下驗證用戶口令君珠。

三? import的使用

import 模塊 先要怎么樣?

import tbjx 執(zhí)行一次tbjx這個模塊里面的所有代碼,

第一次引用tbjx這個模塊,會將這個模塊里面的所有代碼加載到內存,只要你的程序沒有結束,接下來你在

引用多少次,它會先從內存中尋找有沒有此模塊,如果已經加載到內存,就不再重復加載.

第一次導入模塊執(zhí)行三件事 ***

1. 在內存中創(chuàng)建一個以tbjx命名的名稱空間.

2. 執(zhí)行此名稱空間所有的可執(zhí)行代碼(將tbjx.py文件中所有的變量與值的對應關系加載到這

個名稱空間).

3. 通過tbjx. 的方式引用模塊里面的代碼.

import tbjx

print(tbjx.name)

tbjx.read1()

被導入模塊有獨立的名稱空間 ***

import tbjx

# name = 'alex'

# print(name)

# print(tbjx.name)

#

# def read1():

# print(666)

# tbjx.read1()

#

# name = '日天'

# tbjx.change()

# print(name) # 日天

# print(tbjx.name) # barry

為模塊起別名 **

1 簡單,便捷.

# import hfjksdahdsafkd as sm

# print(sm.name)

2,有利于代碼的簡化.

# 原始寫法

# result = input('請輸入')

# if result == 'mysql':

# import mysql1

# mysql1.mysql()

# elif result == 'oracle':

# import oracle1

# oracle1.oracle()

# list.index()

# str.index()

# tuple.index()

# 起別名

# result = input('請輸入')

# if result == 'mysql':

# import mysql1 as sm

# elif result == 'oracle':

# import oracle1 as sm

# ''' 后面還有很多'''

# sm.db() # 統(tǒng)一接口,歸一化思想

導入多個模塊

import time, os, sys # 這樣寫不好

# 應該向以下這種寫法:

import time

import os

import sys

from ... import ...

from ... import ...的使用

# from tbjx import name

# from tbjx import read1

# from tbjx import read2

# print(name)

# print(globals())

# read1()

from ... import ... 與import對比 ***

1. from.. import 用起來更方便

from tbjx import name

print(name)

2. from...import 容易與本文件的名字產生沖突.

# 1, 容易產生沖突,后者將前者覆蓋

# name = 'alex'

# from tbjx import name

# print(name)

3. 當前位置直接使用read1和read2,執(zhí)行時,仍然以tbjx.py文件全局名稱空間 ***

# from tbjx import read1

#

# def read1():

# print(666)

# name = '大壯'

# read1()

# print(globals())

from tbjx import change

name = 'Alex'

print(name) # 'Alex'

change() # 'barry'

from tbjx import name

print(name)

一行導入多個

from tbjx import name,read1,read2 # 這樣不好

from tbjx import name

from tbjx import read1

from ... import *

模塊循環(huán)導入的問題

py文件的兩種功能py文件的兩個功能:

1. 自己用 腳本

2. 被別人引用 模塊使用

# print('from the tbjx.py')

__all__ = ['name', 'read1'] # 配合*使用

name = '太白金星'

def read1():

print('tbjx模塊:', name)

def read2():

print('tbjx模塊')

read1()

def change():

global name

name = 'barry'

print(name)

# print(__name__)

# 當tbjx.py做腳本: __name__ == __main__ 返回True

# 當tbjx.py做模塊被別人引用時: __name__ == tbjx

# __name__ 根據文件的扮演的角色(腳本,模塊)不同而得到不同的結果

#1, 模塊需要調試時,加上 if __name__ == '__main__':

# import time

# change() # 測試代碼

# if __name__ == '__main__':

# change()

# 2, 作為項目的啟動文件需要用

模塊的搜索路徑

# import sm

import abc

# python 解釋器會自動將一些內置內容(內置函數,內置模塊等等)加載到內存中

import sys

# print(sys.modules) # 內置內容(內置函數,內置模塊等等)

import time

# print(sys.path)

#['D:\\python_22\\day17', 'C:\\Python\\Python36\\python36.zip',

'C:\\Python\\Python36\\DLLs', 'C:\\Python\\Python36\\lib',

'C:\\Python\\Python36', 'C:\\Python\\Python36\\lib\\site-packages']# 'D:\\python_22\\day17' 路徑是當前執(zhí)行文件的相對路徑

# import tbjx

# 我就想找到dz 內存沒有,內置中,這兩個你左右不了,sys.path你可以操作.

import sys

sys.path.append(r'D:\python_22\day16')

# sys.path 會自動將你的 當前目錄的路徑加載到列表中.

import dz

# 如果你想要引用你自定義的模塊:

# 要不你就將這個模塊放到當前目錄下面,要不你就手動添加到sys.path

import sm

1. 它會先從內存中尋找有沒有已經存在的以sm命名的名稱空間.

2. 它會從內置的模塊中找. time,sys,os,等等.

3. 他從sys.path中尋找.

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末娇斑,一起剝皮案震驚了整個濱河市策添,隨后出現的幾起案子,更是在濱河造成了極大的恐慌毫缆,老刑警劉巖唯竹,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異悔醋,居然都是意外死亡摩窃,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門芬骄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來猾愿,“玉大人,你說我怎么就攤上這事账阻〉倜兀” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵淘太,是天一觀的道長姻僧。 經常有香客問我,道長蒲牧,這世上最難降的妖魔是什么撇贺? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮冰抢,結果婚禮上松嘶,老公的妹妹穿的比我還像新娘。我一直安慰自己挎扰,他們只是感情好翠订,可當我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著遵倦,像睡著了一般尽超。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上梧躺,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天似谁,我揣著相機與錄音,去河邊找鬼。 笑死棘脐,一個胖子當著我的面吹牛斜筐,可吹牛的內容都是我干的。 我是一名探鬼主播蛀缝,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼目代!你這毒婦竟也來了屈梁?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤榛了,失蹤者是張志新(化名)和其女友劉穎在讶,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體霜大,經...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡构哺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了战坤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片曙强。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖途茫,靈堂內的尸體忽然破棺而出碟嘴,到底是詐尸還是另有隱情,我是刑警寧澤囊卜,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布娜扇,位于F島的核電站,受9級特大地震影響栅组,放射性物質發(fā)生泄漏雀瓢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一玉掸、第九天 我趴在偏房一處隱蔽的房頂上張望刃麸。 院中可真熱鬧,春花似錦排截、人聲如沸嫌蚤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽脱吱。三九已至,卻和暖如春认罩,著一層夾襖步出監(jiān)牢的瞬間箱蝠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宦搬,地道東北人牙瓢。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像间校,于是被迫代替她去往敵國和親矾克。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,678評論 2 354