Python基礎(十三)—切片、yield、生成器、序列化JSON

切片 Slice

切片操作基本表達式:object[start_index:end_index:step]

  • 表達式解釋
    • step爲步長參數,類似range()裏的步長參數。得到的序列從starting_index(包含starting_index)開始,每次以步長前進,即starting_index + step,直到ending_index(不包含ending_index)結束。
    • step:正負數均可,其絕對值大小決定了切取數據時的‘‘步長”,而正負號決定了“切取方向”,正表示“從左往右”取值,負表示“從右往左”取值。當step省略時,默認爲1,即從左往右以增量1取值。
    • start_index:表示起始索引(包含該索引本身);該參數省略時,表示從對象“端點”開始取值,至於是從“起點”還是從“終點”開始,則由step參數的正負決定,step爲正從“起點”開始,爲負從“終點”開始。
    • end_index:表示終止索引(不包含該索引本身);該參數省略時,表示一直取到數據“端點”,至於是到“起點”還是到“終點”,同樣由step參數的正負決定,step爲正時直到“終點”,爲負時直到“起點”。

簡單的來說,就是start_index、end_index確定起始兩個點及方向(start_index -> end_index),而step則是確定方向和步長。

  • 例子
list = ['a', 'b', 'c', 'd', 'e', 'f', 'g']

print(list[5:3])  # 默認1表示從左往右取值,start_index=5到end_index=3決定了從左往右取值,矛盾,爲空

print(list[1:3:-1])  # -1表示從右往左取值,start_index=1到end_index=3決定了從右往左取值,矛盾,爲空
print(list[5:3:-1])  # -1表示從右往左取值,start_index=5(f)到end_index=3(d)決定了從左往右取值,['f', 'e']

print(list[-1:3:1])  # 1表示從左往右取值,start_index=-1(g)在end_index=3(d)的右邊,因此方向從右往左取值,矛盾,[]
print(list[1:-3:1])  # 1表示從左往右取值,start_index=1(b)在end_index=-3(e)的左邊,因此方向從右往左取值,['b', 'c', 'd']

print(list[-2:-5:-1])  # -1表示從右往左取值,start_index=-2(f)在end_index=3(c)的右邊,因此方向從右往左取值,['f', 'e', 'd']
print(list[-2:-5:1])  # 1表示從左往右取值,start_index=-2(f)在end_index=3(c)的右邊,因此方向從右往左取值,矛盾,[]

yield

首先上一個講解yield很好的博文:https://blog.csdn.net/mieleizhi0522/article/details/82142856#commentBox

  • 先將yield看成return
    如果你還沒有對yield有個初步分認識,那麼你先把yield看做“return”,這個是直觀的,它首先是個return,普通的return是什麼意思,就是在程序中返回某個值,返回之後程序就不再往下運行了,但是使用yield以下代碼及結果會是這樣的:
def foo():
    print("starting...")
    while True:
        res = yield 4
        print("res:", res)
g = foo()
print(next(g))
print("*"*20)
print(next(g))

"""
starting...
4
********************
res: None
4
"""
  • 以上代碼單步調試
    • 1.程序開始執行以後,因爲foo函數中有yield關鍵字,所以foo函數並不會真的執行,而是先得到一個生成器g(相當於一個對象);
    • 2.直到調用next方法,foo函數正式開始執行,先執行foo函數中的print方法,然後進入while循環
    • 3.程序遇到yield關鍵字,然後把yield想想成return,return了一個4之後,程序停止,並沒有執行賦值給res操作,此時next(g)語句執行完成,所以輸出的前兩行(第一個是while上面的print的結果,第二個是return出的結果)是執行print(next(g))的結果
    • 4.程序執行print("*"20),輸出20個
    • 5.又開始執行下面的print(next(g)),這個時候和上面那個差不多,不過不同的是,這個時候是從剛纔那個next程序停止的地方開始執行的,也就是要執行res的賦值操作,這時候要注意,這個時候賦值操作的右邊是沒有值的(因爲剛纔那個是return出去了,並沒有給賦值操作的左邊傳參數),所以這個時候res賦值是None,所以接着下面的輸出就是res:None
    • 6.程序會繼續在while裏執行,又一次碰到yield,這個時候同樣return 出4,然後程序停止,print函數輸出的4就是這次return出的4。
  • yield和return的關係和區別
    帶yield的函數是一個生成器,而不是一個函數了,這個生成器有一個函數就是next函數,next就相當於“下一步”生成哪個數,這一次的next開始的地方是接着上一次的next停止的地方執行的,所以調用next的時候,生成器並不會從foo函數的開始執行,只是接着上一步停止的地方開始,然後遇到yield後,return出要生成的數,此步就結束。
  • next()和send()
    上面已經說到,next()是接着上一次的next停止的地方執行,而send是發送一個參數給res,使用send的話,開始執行的時候,先接着上一次(return 4之後)執行,先把7賦值給了res,然後執行next的作用,代碼如下:
def foo():
    print("starting...")
    while True:
        res = yield 4
        print("res:",res)
g = foo()
print(next(g))
print("*"*20)
print(g.send(7))

"""
starting...
4
********************
res: 7
4
"""
5.程序執行g.send(7),程序會從yield關鍵字那一行繼續向下運行,send會把7這個值賦值給res變量
6.由於send方法中包含next()方法,所以程序會繼續向下運行執行print方法,然後再次進入while循環
7.程序執行再次遇到yield關鍵字,yield會返回後面的值後,程序再次暫停,直到再次調用next方法或send方法。

生成器 generator

  • 生成器的定義
    根據以上yield的例子,其實我們應該清楚了,在python中,一遍循環一邊計算的機制,成爲生成器:generator
L = [x * x for x in range(10)]
print(L)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
g = (x * x for x in range(10))
print(g)  # <generator object <genexpr> at 0x02F1D630>
  • 類似於列表生成式的生成器循環
    每次使用next()來獲取下一個元素,當無元素是,拋出StopIteration的異常。當然也可以使用循環in,這樣就不用了擔心StopIteration異常。

  • 函數+yield的生成器
    下面通過斐波那契數列的生成器,進行進一步的講解。

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a+b
        n = n+1
    return 'done'

for i in fib(5):
    print(i)

# 爲了獲取return 'done',必須捕獲StopIteration的異常
g = fib(5)
while True:
    try:
        print(next(g))
    except StopIteration as e:
        print('return %s' % e.value)
        break

序列化pickling、JSON

  • pickling
    pickling前面已經講過了,pickling前面已經講過,雖然可以保存數據,但是卻只能用於Python,並且不同的版本之間彼此可能都不兼容。只適合保存那些不重要的數據,不能反序列化也沒關係。下面主要講更符合Web標準的JSON序列化。
  • JSON
    JSON不僅是標準格式,並且比XML更快,也可以在Web頁面中直接讀取,非常方便。
    • python數據類型與json數據類型的映射關係
Python JSON
dict object
list, tuple array
str, unicode string
int, long, float number
TRUE TRUE
FALSE FALSE
None null
  • JSON的方法
方法 描述
json.dumps() 將 Python 對象編碼成 JSON 字符串
json.loads() 將已編碼的 JSON 字符串解碼爲 Python 對象
json.dump() 將Python內置類型序列化爲json對象後寫入文件
json.load() 讀取文件中json形式的字符串元素轉化爲Python類型
  • python對象轉換爲json
    以下是將元組、字典、列表等轉化爲JSON格式的數據。由於json.dumps 進行序列化時,默認使用ascii編碼,因此有中文進行序列化時,需要加上ensure_ascii=False。
import json

t = ('lz', 18)
print('t:', json.dumps(t))

di = dict(name='\u7f57\u6b63', age='18')
print('di:', json.dumps(di, ensure_ascii=False))

d = {1:'a', 'b':2, 3: 4}
print('d:', json.dumps(d))

list = [{'a':'A', 2:'B', 'c':3}, ['d', 4], 'e', 5]
print('list:', json.dumps(list))
"""
t: ["lz", 18]
di: {"name": "羅正", "age": "18"}
d: {"1": "a", "b": 2, "3": 4}
list: [{"a": "A", "2": "B", "c": 3}, ["d", 4], "e", 5]
"""
  • json轉爲python對象
import json
def json_to_dict():
    data = '''
    {
    "name": "Python書籍",
    "origin_price": 66,
    "pub_date": "2018-4-14 17:00:00",
    "store": ["京東", "淘寶"],
    "author": ["張三", "李四", "Jhone"],
    "is_valid": true,
    "is_sale": false,
    "meta": {
        "isbn": "abc-123",
        "pages": 300
    },
    "desc": null
    }
    '''
    res = json.loads(data)
    print(res)
    return res
if __name__ == '__main__':

    res1 = json_to_dict()
    print(type(res1))
"""
{'name': 'Python書籍', 'origin_price': 66, 'pub_date': '2018-4-14 17:00:00', 'store': ['京東', '淘寶'], 'author': ['張三', '李四', 'Jhone'], 'is_valid': True, 'is_sale': False, 'meta': {'isbn': 'abc-123', 'pages': 300}, 'desc': None}
<class 'dict'>
"""

個人博客:Loak 正 - 關注人工智能及互聯網的個人博客
文章地址:Python基礎(十三)—切片、yield、生成器、序列化JSON

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章