Day4 裝飾器——迭代器——生成器

一 裝飾器

1.1 函數對象

一 函數是第一類對象,即函數能夠看成數據傳遞python

#1 能夠被引用
#2 能夠看成參數傳遞
#3 返回值能夠是函數
#3 能夠看成容器類型的元素

二 利用該特性,優雅的取代多分支的ifmysql

def foo():
    print('foo')

def bar():
    print('bar')

dic={
    'foo':foo,
    'bar':bar,
}
while True:
    choice=input('>>: ').strip()
    if choice in dic:
        dic[choice]()

1.2 函數嵌套

一 函數的嵌套調用linux

def max(x,y):
    return x if x > y else y

def max4(a,b,c,d):
    res1=max(a,b)
    res2=max(res1,c)
    res3=max(res2,d)
    return res3
print(max4(1,2,3,4))

二 函數的嵌套定義git

def f1():
    def f2():
        def f3():
            print('from f3')
        f3()
    f2()

f1()
f3() #報錯,爲什麼?請看下一小節

1.3 名稱空間和做用域

一 什麼是名稱空間?redis

#名稱空間:存放名字的地方,三種名稱空間,(以前遺留的問題x=1,1存放於內存中,那名字x存放在哪裏呢?名稱空間正是存放名字x與1綁定關係的地方)

二 名稱空間的加載順序sql

python test.py
#一、python解釋器先啓動,於是首先加載的是:內置名稱空間
#二、執行test.py文件,而後以文件爲基礎,加載全局名稱空間
#三、在執行文件的過程當中若是調用函數,則臨時產生局部名稱空間

三 名字的查找順序express

局部名稱空間--->全局名稱空間--->內置名稱空間

#須要注意的是:在全局沒法查看局部的,在局部能夠查看全局的,以下示例

# max=1
def f1():
    # max=2
    def f2():
        # max=3
        print(max)
    f2()
f1()
print(max)

四 做用域編程

#一、做用域即範圍
        - 全局範圍(內置名稱空間與全局名稱空間屬於該範圍):全局存活,全局有效
      - 局部範圍(局部名稱空間屬於該範圍):臨時存活,局部有效
#二、做用域關係是在函數定義階段就已經固定的,與函數的調用位置無關,以下
x=1
def f1():
    def f2():
        print(x)
    return f2
x=100
def f3(func):
    x=2
    func()
x=10000
f3(f1())

#三、查看做用域:globals(),locals()


LEGB 表明名字查找順序: locals -> enclosing function -> globals -> __builtins__
locals 是函數內的名字空間,包括局部變量和形參
enclosing 外部嵌套函數的名字空間(閉包中常見)
globals 全局變量,函數定義所在模塊的名字空間
builtins 內置模塊的名字空間

五 global與nonlocal關鍵字json

1.4 閉包函數

一 什麼是閉包?緩存

 

#內部函數包含對外部做用域而非全局做用域的引用

#提示:以前咱們都是經過參數將外部的值傳給函數,閉包提供了另一種思路,包起來嘍,包起呦,包起來哇

        def counter():
            n=0
            def incr():
                nonlocal n
                x=n
                n+=1
                return x
            return incr

        c=counter()
        print(c())
        print(c())
        print(c())
        print(c.__closure__[0].cell_contents) #查看閉包的元素

二 閉包的意義與應用

#閉包的意義:返回的函數對象,不只僅是一個函數對象,在該函數外還包裹了一層做用域,這使得,該函數不管在何處調用,優先使用本身外層包裹的做用域
#應用領域:延遲計算(原來咱們是傳參,如今咱們是包起來)
    from urllib.request import urlopen

    def index(url):
        def get():
            return urlopen(url).read()
        return get

    baidu=index('http://www.baidu.com')
    print(baidu().decode('utf-8'))

1.5 裝飾器

一 爲什麼要用裝飾器

#開放封閉原則:對修改封閉,對擴展開放

二 什麼是裝飾器

裝飾器他人的器具,自己能夠是任意可調用對象,被裝飾者也能夠是任意可調用對象。
強調裝飾器的原則:1 不修改被裝飾對象的源代碼 2 不修改被裝飾對象的調用方式
裝飾器的目標:在遵循1和2的前提下,爲被裝飾對象添加上新功能

三 裝飾器的使用

import time
def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
        return res
    return wrapper

@timmer
def foo():
    time.sleep(3)
    print('from foo')
foo()

無參裝飾器
無參裝飾器
def auth(driver='file'):
    def auth2(func):
        def wrapper(*args,**kwargs):
            name=input("user: ")
            pwd=input("pwd: ")

            if driver == 'file':
                if name == 'egon' and pwd == '123':
                    print('login successful')
                    res=func(*args,**kwargs)
                    return res
            elif driver == 'ldap':
                print('ldap')
        return wrapper
    return auth2

@auth(driver='file')
def foo(name):
    print(name)

foo('egon')

有參裝飾器
有參裝飾器

四 裝飾器語法

被裝飾函數的正上方,單獨一行
        @deco1
        @deco2
        @deco3
        def foo():
            pass

        foo=deco1(deco2(deco3(foo)))

五 裝飾器補充:wraps

from functools import wraps

def deco(func):
    @wraps(func) #加在最內層函數正上方
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper

@deco
def index():
    '''哈哈哈哈'''
    print('from index')

print(index.__doc__)

六 練習

一:編寫函數,(函數執行的時間是隨機的)
二:編寫裝飾器,爲函數加上統計時間的功能
三:編寫裝飾器,爲函數加上認證的功能

四:編寫裝飾器,爲多個函數加上認證的功能(用戶的帳號密碼來源於文件),要求登陸成功一次,後續的函數都無需再輸入用戶名和密碼
注意:從文件中讀出字符串形式的字典,能夠用eval('{"name":"egon","password":"123"}')轉成字典格式

五:編寫裝飾器,爲多個函數加上認證功能,要求登陸成功一次,在超時時間內無需重複登陸,超過了超時時間,則必須從新登陸

六:編寫下載網頁內容的函數,要求功能是:用戶傳入一個url,函數返回下載頁面的結果

七:爲題目五編寫裝飾器,實現緩存網頁內容的功能:
具體:實現下載的頁面存放於文件中,若是文件內有值(文件大小不爲0),就優先從文件中讀取網頁內容,不然,就去下載,而後存到文件中

擴展功能:用戶能夠選擇緩存介質/緩存引擎,針對不一樣的url,緩存到不一樣的文件中

八:還記得咱們用函數對象的概念,製做一個函數字典的操做嗎,來來來,咱們有更高大上的作法,在文件開頭聲明一個空字典,而後在每一個函數前加上裝飾器,完成自動添加到字典的操做

九 編寫日誌裝飾器,實現功能如:一旦函數f1執行,則將消息2017-07-21 11:12:11 f1 run寫入到日誌文件中,日誌文件路徑能夠指定
注意:時間格式的獲取
import time
time.strftime('%Y-%m-%d %X')

#題目一:
import time,random
ran = random.random()
def foo():
    time.sleep(ran)
    print("Done")
foo()
#題目二:
import time,random
ran = random.random()
def timer(func):
    def inner():
        start_time = time.time()
        func()
        stop_time = time.time()
        print("TIME>> %s" %(stop_time-start_time))
    return inner
@timer
def foo():
    time.sleep(ran)
    print("Done")
foo()
#題目三:
import time,random
ran = random.random()
def auth(bar):
    def inner():
        info = {
            "lizhong":123,
            "hehe":234,
        }
        name = input("user>>").strip()
        if name in info:
            pwd = int(input("pwd>>").strip())
            if pwd == info[name]:
                print("Login success")
                bar()
            else:
                print("Login faild")
        else:
            print("No such user")
    return inner
def timer(func):
    def inner():
        start_time = time.time()
        func()
        stop_time = time.time()
        print("TIME>> %s" %(stop_time-start_time))
    return inner
@auth
@timer
def foo():
    time.sleep(ran)
    print("Done")
while True:
    foo()
#題目四:
db='db.txt'
login_status={'user':None,'status':False}
def auth(auth_type='file'):
    def auth2(func):
        def wrapper(*args,**kwargs):
            if login_status['user'] and login_status['status']:
                return func(*args,**kwargs)
            if auth_type == 'file':
                with open(db,encoding='utf-8') as f:
                    dic=eval(f.read())
                name=input('username: ').strip()
                password=input('password: ').strip()
                if name in dic and password == dic[name]:
                    login_status['user']=name
                    login_status['status']=True
                    res=func(*args,**kwargs)
                    return res
                else:
                    print('username or password error')
            elif auth_type == 'sql':
                pass
            else:
                pass
        return wrapper
    return auth2

@auth()
def index():
    print('index')

@auth(auth_type='file')
def home(name):
    print('welcome %s to home' %name)


# index()
# home('egon')

#題目五
import time,random
user={'user':None,'login_time':None,'timeout':0.000003,}

def timmer(func):
    def wrapper(*args,**kwargs):
        s1=time.time()
        res=func(*args,**kwargs)
        s2=time.time()
        print('%s' %(s2-s1))
        return res
    return wrapper


def auth(func):
    def wrapper(*args,**kwargs):
        if user['user']:
            timeout=time.time()-user['login_time']
            if timeout < user['timeout']:
                return func(*args,**kwargs)
        name=input('name>>: ').strip()
        password=input('password>>: ').strip()
        if name == 'egon' and password == '123':
            user['user']=name
            user['login_time']=time.time()
            res=func(*args,**kwargs)
            return res
    return wrapper

@auth
def index():
    time.sleep(random.randrange(3))
    print('welcome to index')

@auth
def home(name):
    time.sleep(random.randrange(3))
    print('welcome %s to home ' %name)

index()
home('egon')

#題目六:
import requests
import os
def wget(url):
    res = requests.get(url)
    return res
print(wget("http://baidu.com/"))
#題目七:簡單版本
import requests
import os
cache_file='cache.txt'
def make_cache(func):
    def wrapper(*args,**kwargs):
        if not os.path.exists(cache_file):
            with open(cache_file,'w'):pass

        if os.path.getsize(cache_file):
            with open(cache_file,'r',encoding='utf-8') as f:
                res=f.read()
        else:
            res=func(*args,**kwargs)
            with open(cache_file,'w',encoding='utf-8') as f:
                f.write(res)
        return res
    return wrapper

@make_cache
def get(url):
    return requests.get(url).text


# res=get('https://www.python.org')

# print(res)

#題目七:擴展版本
import requests,os,hashlib
engine_settings={
    'file':{'dirname':'./db'},
    'mysql':{
        'host':'127.0.0.1',
        'port':3306,
        'user':'root',
        'password':'123'},
    'redis':{
        'host':'127.0.0.1',
        'port':6379,
        'user':'root',
        'password':'123'},
}

def make_cache(engine='file'):
    if engine not in engine_settings:
        raise TypeError('egine not valid')
    def deco(func):
        def wrapper(url):
            if engine == 'file':
                m=hashlib.md5(url.encode('utf-8'))
                cache_filename=m.hexdigest()
                cache_filepath=r'%s/%s' %(engine_settings['file']['dirname'],cache_filename)

                if os.path.exists(cache_filepath) and os.path.getsize(cache_filepath):
                    return open(cache_filepath,encoding='utf-8').read()

                res=func(url)
                with open(cache_filepath,'w',encoding='utf-8') as f:
                    f.write(res)
                return res
            elif engine == 'mysql':
                pass
            elif engine == 'redis':
                pass
            else:
                pass

        return wrapper
    return deco

@make_cache(engine='file')
def get(url):
    return requests.get(url).text

# print(get('https://www.python.org'))
print(get('https://www.baidu.com'))


#題目八
route_dic={}

def make_route(name):
    def deco(func):
        route_dic[name]=func
    return deco
@make_route('select')
def func1():
    print('select')

@make_route('insert')
def func2():
    print('insert')

@make_route('update')
def func3():
    print('update')

@make_route('delete')
def func4():
    print('delete')

print(route_dic)


#題目九
import time
import os

def logger(logfile):
    def deco(func):
        if not os.path.exists(logfile):
            with open(logfile,'w'):pass

        def wrapper(*args,**kwargs):
            res=func(*args,**kwargs)
            with open(logfile,'a',encoding='utf-8') as f:
                f.write('%s %s run\n' %(time.strftime('%Y-%m-%d %X'),func.__name__))
            return res
        return wrapper
    return deco

@logger(logfile='aaaaaaaaaaaaaaaaaaaaa.log')
def index():
    print('index')

index()
View Code

 

二 迭代器和生成器

2.1 迭代器

一 迭代的概念

#迭代是一個重複的過程,每次重複即一次迭代,而且每次迭代的結果都是下一次迭代的初始值
while True: #只是單純地重複,於是不是迭代
    print('===>') 
    
l=[1,2,3]
count=0
while count < len(l): #迭代
    print(l[count])
    count+=1

二 爲什麼要有迭代器?什麼是可迭代對象?什麼是迭代器對象?

#一、爲什麼要有迭代器?
對於序列類型:字符串、列表、元組,咱們可使用索引的方式迭代取出其包含的元素。但對於字典、集合、文件等類型是沒有索引的,若還想取出其內部包含的元素,則必須找出一種不依賴於索引的迭代方式,這就是迭代器

#二、什麼是可迭代對象?
可迭代對象指的是內置有__iter__方法的對象,即obj.__iter__,以下
'hello'.__iter__
(1,2,3).__iter__
[1,2,3].__iter__
{'a':1}.__iter__
{'a','b'}.__iter__
open('a.txt').__iter__

#三、什麼是迭代器對象?
可迭代對象執行obj.__iter__()獲得的結果就是迭代器對象
而迭代器對象指的是即內置有__iter__又內置有__next__方法的對象

文件類型是迭代器對象
open('a.txt').__iter__()
open('a.txt').__next__()


#四、注意:
迭代器對象必定是可迭代對象,而可迭代對象不必定是迭代器對象

三 迭代器對象的使用

dic={'a':1,'b':2,'c':3}
iter_dic=dic.__iter__() #獲得迭代器對象,迭代器對象即有__iter__又有__next__,可是:迭代器.__iter__()獲得的仍然是迭代器自己
iter_dic.__iter__() is iter_dic #True

print(iter_dic.__next__()) #等同於next(iter_dic)
print(iter_dic.__next__()) #等同於next(iter_dic)
print(iter_dic.__next__()) #等同於next(iter_dic)
# print(iter_dic.__next__()) #拋出異常StopIteration,或者說結束標誌

#有了迭代器,咱們就能夠不依賴索引迭代取值了
iter_dic=dic.__iter__()
while 1:
    try:
        k=next(iter_dic)
        print(dic[k])
    except StopIteration:
        break
        
#這麼寫太醜陋了,須要咱們本身捕捉異常,控制next,python這麼牛逼,能不能幫我解決呢?能,請看for循環

四 for循環

#基於for循環,咱們能夠徹底再也不依賴索引去取值了
dic={'a':1,'b':2,'c':3}
for k in dic:
    print(dic[k])

#for循環的工做原理
#1:執行in後對象的dic.__iter__()方法,獲得一個迭代器對象iter_dic
#2: 執行next(iter_dic),將獲得的值賦值給k,而後執行循環體代碼
#3: 重複過程2,直到捕捉到異常StopIteration,結束循環

五 迭代器的優缺點

#優勢:
  - 提供一種統一的、不依賴於索引的迭代方式
  - 惰性計算,節省內存
#缺點:
  - 沒法獲取長度(只有在next完畢才知道到底有幾個值)
  - 一次性的,只能日後走,不能往前退

2.2 生成器

一 什麼是生成器

#只要函數內部包含有yield關鍵字,那麼函數名()的到的結果就是生成器,而且不會執行函數內部代碼

def func():
    print('====>first')
    yield 1
    print('====>second')
    yield 2
    print('====>third')
    yield 3
    print('====>end')

g=func()
print(g) #<generator object func at 0x0000000002184360>

二 生成器就是迭代器

g.__iter__
g.__next__
#二、因此生成器就是迭代器,所以能夠這麼取值
res=next(g)
print(res)

三 練習

一、自定義函數模擬range(1,7,2)

二、模擬管道,實現功能:tail -f access.log | grep '404'

#題目一:
def my_range(start,stop,step=1):
    while start < stop:
        yield start
        start+=step

#執行函數獲得生成器,本質就是迭代器
obj=my_range(1,7,2) #1  3  5
print(next(obj))
print(next(obj))
print(next(obj))
print(next(obj)) #StopIteration

#應用於for循環
for i in my_range(1,7,2):
    print(i)

#題目二
import time
def tail(filepath):
    with open(filepath,'rb') as f:
        f.seek(0,2)
        while True:
            line=f.readline()
            if line:
                yield line
            else:
                time.sleep(0.2)

def grep(pattern,lines):
    for line in lines:
        line=line.decode('utf-8')
        if pattern in line:
            yield line

for line in grep('404',tail('access.log')):
    print(line,end='')

#測試
with open('access.log','a',encoding='utf-8') as f:
    f.write('出錯啦404\n')
View Code

四 協程函數

#yield關鍵字的另一種使用形式:表達式形式的yield
def eater(name):
    print('%s 準備開始吃飯啦' %name)
    food_list=[]
    while True:
        food=yield food_list
        print('%s 吃了 %s' % (name,food))
        food_list.append(food)

g=eater('egon')
g.send(None) #對於表達式形式的yield,在使用時,第一次必須傳None,g.send(None)等同於next(g)
g.send('蒸羊羔')
g.send('蒸鹿茸')
g.send('蒸熊掌')
g.send('燒素鴨')
g.close()
g.send('燒素鵝')
g.send('燒鹿尾')

五 練習
一、編寫裝飾器,實現初始化協程函數的功能

二、實現功能:grep  -rl  'python'  /etc

#題目一:
def init(func):
    def wrapper(*args,**kwargs):
        g=func(*args,**kwargs)
        next(g)
        return g
    return wrapper
@init
def eater(name):
    print('%s 準備開始吃飯啦' %name)
    food_list=[]
    while True:
        food=yield food_list
        print('%s 吃了 %s' % (name,food))
        food_list.append(food)

g=eater('egon')
g.send('蒸羊羔')

#題目二:
#注意:target.send(...)在拿到target的返回值後纔算執行結束
import os
def init(func):
    def wrapper(*args,**kwargs):
        g=func(*args,**kwargs)
        next(g)
        return g
    return wrapper

@init
def search(target):
    while True:
        filepath=yield
        g=os.walk(filepath)
        for dirname,_,files in g:
            for file in files:
                abs_path=r'%s\%s' %(dirname,file)
                target.send(abs_path)
@init
def opener(target):
    while True:
        abs_path=yield
        with open(abs_path,'rb') as f:
            target.send((f,abs_path))
@init
def cat(target):
    while True:
        f,abs_path=yield
        for line in f:
            res=target.send((line,abs_path))
            if res:
                break
@init
def grep(pattern,target):
    tag=False
    while True:
        line,abs_path=yield tag
        tag=False
        if pattern.encode('utf-8') in line:
            target.send(abs_path)
            tag=True
@init
def printer():
    while True:
        abs_path=yield
        print(abs_path)


g=search(opener(cat(grep('你好',printer()))))
# g.send(r'E:\CMS\aaa\db')
g=search(opener(cat(grep('python',printer()))))
g.send(r'E:\CMS\aaa\db')
View Code

六 yield總結

#一、把函數作成迭代器
#二、對比return,能夠返回屢次值,能夠掛起/保存函數的運行狀態

2.3 面向過程編程

#一、首先強調:面向過程編程絕對不是用函數編程這麼簡單,面向過程是一種編程思路、思想,而編程思路是不依賴於具體的語言或語法的。言外之意是即便咱們不依賴於函數,也能夠基於面向過程的思想編寫程序

#二、定義
面向過程的核心是過程二字,過程指的是解決問題的步驟,即先幹什麼再幹什麼

基於面向過程設計程序就比如在設計一條流水線,是一種機械式的思惟方式

#三、優勢:複雜的問題流程化,進而簡單化

#四、缺點:可擴展性差,修改流水線的任意一個階段,都會牽一髮而動全身

#五、應用:擴展性要求不高的場景,典型案例如linux內核,git,httpd

#六、舉例
流水線1:
用戶輸入用戶名、密碼--->用戶驗證--->歡迎界面

流水線2:
用戶輸入sql--->sql解析--->執行功能

三 三元表達式、列表推導式、生成器表達式

3.1 三元表達式

name=input('姓名>>: ')
res='SB' if name == 'alex' else 'NB'
print(res)

3.2 列表推導式

#一、示例
egg_list=[]
for i in range(10):
    egg_list.append('雞蛋%s' %i)

egg_list=['雞蛋%s' %i for i in range(10)]

#二、語法
[expression for item1 in iterable1 if condition1
for item2 in iterable2 if condition2
...
for itemN in iterableN if conditionN
]
相似於
res=[]
for item1 in iterable1:
    if condition1:
        for item2 in iterable2:
            if condition2
                ...
                for itemN in iterableN:
                    if conditionN:
                        res.append(expression)

#三、優勢:方便,改變了編程習慣,可稱之爲聲明式編程

3.3 生成器表達式

#一、把列表推導式的[]換成()就是生成器表達式

#二、示例:生一筐雞蛋變成給你一隻老母雞,用的時候就下蛋,這也是生成器的特性
>>> chicken=('雞蛋%s' %i for i in range(5))
>>> chicken
<generator object <genexpr> at 0x10143f200>
>>> next(chicken)
'雞蛋0'
>>> list(chicken) #因chicken可迭代,於是能夠轉成列表
['雞蛋1', '雞蛋2', '雞蛋3', '雞蛋4',]

#三、優勢:省內存,一次只產生一個值在內存中

3.4 練習

一、將names=['egon','alex_sb','wupeiqi','yuanhao']中的名字所有變大寫

二、將names=['egon','alex_sb','wupeiqi','yuanhao']中以sb結尾的名字過濾掉,而後保存剩下的名字長度

三、求文件a.txt中最長的行的長度(長度按字符個數算,須要使用max函數)

四、求文件a.txt中總共包含的字符個數?思考爲什麼在第一次以後的n次sum求和獲得的結果爲0?(須要使用sum函數)

五、思考題

with open('a.txt') as f:
    g=(len(line) for line in f)
print(sum(g)) #爲什麼報錯?

六、文件shopping.txt內容以下

求總共花了多少錢?

打印出全部商品的信息,格式爲[{'name':'xxx','price':333,'count':3},...]

求單價大於10000的商品信息,格式同上

#題目一
names=['egon','alex_sb','wupeiqi','yuanhao']
names=[name.upper() for name in names]

#題目二
names=['egon','alex_sb','wupeiqi','yuanhao']
names=[len(name) for name in names if not name.endswith('sb')]

#題目三
with open('a.txt',encoding='utf-8') as f:
    print(max(len(line) for line in f))

#題目四
with open('a.txt', encoding='utf-8') as f:
    print(sum(len(line) for line in f))
    print(sum(len(line) for line in f)) #求包換換行符在內的文件全部的字符數,爲什麼獲得的值爲0?
    print(sum(len(line) for line in f)) #求包換換行符在內的文件全部的字符數,爲什麼獲得的值爲0?

#題目五(略)

#題目六:每次必須從新打開文件或seek到文件開頭,由於迭代完一次就結束了
with open('a.txt',encoding='utf-8') as f:
    info=[line.split() for line in f]
    cost=sum(float(unit_price)*int(count) for _,unit_price,count in info)
    print(cost)


with open('a.txt',encoding='utf-8') as f:
    info=[{
        'name': line.split()[0],
        'price': float(line.split()[1]),
        'count': int(line.split()[2]),
    } for line in f]
    print(info)


with open('a.txt',encoding='utf-8') as f:
    info=[{
        'name': line.split()[0],
        'price': float(line.split()[1]),
        'count': int(line.split()[2]),
    } for line in f if float(line.split()[1]) > 10000]
    print(info)
View Code

 四 json & pickle 模塊

以前咱們學習過用eval內置方法能夠將一個字符串轉成python對象,不過,eval方法是有侷限性的,對於普通的數據類型,json.loads和eval都能用,但遇到特殊類型的時候,eval就無論用了,因此eval的重點仍是一般用來執行一個字符串表達式,並返回表達式的值。

import json
x="[null,true,false,1]"
print(eval(x)) #報錯,沒法解析null類型,而json就能夠
print(json.loads(x)) 

什麼是序列化?

咱們把對象(變量)從內存中變成可存儲或傳輸的過程稱之爲序列化,在Python中叫pickling,在其餘語言中也被稱之爲serialization,marshalling,flattening等等,都是一個意思。

爲何要序列化?

1:持久保存狀態

需知一個軟件/程序的執行就在處理一系列狀態的變化,在編程語言中,'狀態'會以各類各樣有結構的數據類型(也可簡單的理解爲變量)的形式被保存在內存中。

內存是沒法永久保存數據的,當程序運行了一段時間,咱們斷電或者重啓程序,內存中關於這個程序的以前一段時間的數據(有結構)都被清空了。

在斷電或重啓程序以前將程序當前內存中全部的數據都保存下來(保存到文件中),以便於下次程序執行可以從文件中載入以前的數據,而後繼續執行,這就是序列化。

具體的來講,你玩使命召喚闖到了第13關,你保存遊戲狀態,關機走人,下次再玩,還能從上次的位置開始繼續闖關。或如,虛擬機狀態的掛起等。

2:跨平臺數據交互

序列化以後,不只能夠把序列化後的內容寫入磁盤,還能夠經過網絡傳輸到別的機器上,若是收發的雙方約定好實用一種序列化的格式,那麼便打破了平臺/語言差別化帶來的限制,實現了跨平臺數據交互。

反過來,把變量內容從序列化的對象從新讀到內存裏稱之爲反序列化,即unpickling。

如何序列化之json和pickle:

json

若是咱們要在不一樣的編程語言之間傳遞對象,就必須把對象序列化爲標準格式,好比XML,但更好的方法是序列化爲JSON,由於JSON表示出來就是一個字符串,能夠被全部語言讀取,也能夠方便地存儲到磁盤或者經過網絡傳輸。JSON不只是標準格式,而且比XML更快,並且能夠直接在Web頁面中讀取,很是方便。

JSON表示的對象就是標準的JavaScript語言的對象,JSON和Python內置的數據類型對應以下:

import json
 
dic={'name':'alvin','age':23,'sex':'male'}
print(type(dic))#<class 'dict'>
 
j=json.dumps(dic)
print(type(j))#<class 'str'>
json.dump(obj,文件對象(w方式))
json.load(文件對象(r模式)

f=open('序列化對象','w') f.write(j) #-------------------等價於json.dump(dic,f) f.close() #-----------------------------反序列化<br> import json f=open('序列化對象') data=json.loads(f.read())# 等價於data=json.load(f)

pickle

 

import pickle
 
dic={'name':'alvin','age':23,'sex':'male'}
 
print(type(dic))#<class 'dict'>
 
j=pickle.dumps(dic)
print(type(j))#<class 'bytes'>
 
 
f=open('序列化對象_pickle','wb')#注意是w是寫入str,wb是寫入bytes,j是'bytes'
f.write(j)  #-------------------等價於pickle.dump(dic,f)
 
f.close()
#-------------------------反序列化
import pickle
f=open('序列化對象_pickle','rb')
 
data=pickle.loads(f.read())#  等價於data=pickle.load(f)
 
 
print(data['age'])

Pickle的問題和全部其餘編程語言特有的序列化問題同樣,就是它只能用於Python,而且可能不一樣版本的Python彼此都不兼容,所以,只能用Pickle保存那些不重要的數據,不能成功地反序列化也不要緊。

相關文章
相關標籤/搜索