Python的平凡之路(4)

1、迭代器&生成器
生成器定義:
經過列表生成式,咱們能夠直接建立一個列表。可是,受到內存限制,列表容量確定是有限的。並且,建立一個包含100萬個元素的列表,不只佔用很大的存儲空間,若是咱們僅僅須要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了。因此,若是列表元素能夠按照某種算法推算出來,那咱們是否能夠在循環的過程當中不斷推算出後續的元素呢?這樣就沒必要建立完整的list,從而節省大量的空間。在Python中,這種一邊循環一邊計算的機制稱爲生成器。
特色:
1 生成器只有在調用時才能生成相應的數據。
2 只有一個__next__()方法
生成器表達式的語法和列表解析同樣,只不過生成器表達式是被()括起來的,而不是[]
4 生成器是一種特殊的迭代器,內部支持了生成器協議,不須要明肯定義__iter__()和next()方法
5 生成器經過生成器函數產生,生成器函數能夠經過常規的def語句來定義,可是不用return返回,而是用yield一次返回一個結果。
 
列表生成式
譬如:
( i*2 for i in range(10))
等同於
a = [ ]
for i in range(10):
     a.append(i*2)
     print(i)
 
迭代器定義:
咱們已經知道,能夠直接做用於 for循環的數據類型有如下幾種:
一類是集合數據類型,如 listtupledictsetstr等;
一類是 generator,包括生成器和帶 yield的generator function。
這些能夠直接做用於 for循環的對象統稱爲可迭代對象: Iterable
可使用 isinstance()判斷一個對象是不是 Utterable對象。
*能夠被next()函數調用並不斷返回下一個值的對象稱爲迭代器:Iterator
特色:
1生成器都是 Iterator對象,但 listdictstr雖然是 Iterable,卻不是 Iterator
listdictstrIterable變成 Iterator可使用 iter()函數:
2 是可做用於 for循環的對象都是 Iterable類型; 凡是可做用於 next()函數的對象都是 Iterator類型,它們表示一個惰性計算的序列;
集合數據類型如 listdictstr等是 Iterable但不是 Iterator,不過能夠經過 iter()函數得到一個 Iterator對象。
Python的 for循環本質上就是經過不斷調用 next()函數實現的
3 舉例:
Python的 for循環本質上就是經過不斷調用 next()函數實現的, 對於可迭代對象,for語句能夠經過iter()方法獲取迭代器,而且經過next()方法得到容器的下一個元素。例如:
for  in  [ 1 2 3 4 5 ]:
     pass

實際上徹底等價於:python

# 首先得到Iterator對象:
it = iter([1, 2, 3, 4, 5])
# 循環:
while True:
    try:
        # 得到下一個值:
        x = next(it)
    except StopIteration:
        # 遇到StopIteration就退出循環
        break
 
生成器.py
#!/usr/bin/env python
#Author is wspikh
# -*- coding: encoding -*-
#這1億個數並無真正生成,調用的時候才生成。
b = (i*2 for i in range(100))
#b.__next__()) 的含義

for i in b:
    print(i)

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        #print(b)
        yield b #返回了函數的中斷狀態
        a, b = b, a + b
        n = n + 1
    return 'done'
print(fib(100))
f = fib(100)
print(f.__next__())
print("===========")
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())


g = fib(6)
while True:
    try:
        x = next(g)
        print('g:', x)
    except StopIteration as e:
        print('Generator return value:', e.value)
        break
 
迭代器.py
#!/usr/bin/env python
#Author is wspikh
# -*- coding: encoding -*-
from collections import Iterable
#判斷是否是可迭代對象
print(isinstance('abc',Iterable))
print(isinstance('[1,2,3]',Iterable))
print(isinstance('{"server":"192.168.1.10"}',Iterable))
print(isinstance((x for x in range(10)), Iterable))
print(isinstance(100,Iterable))
print("")
print("")
from collections import Iterator
#判斷是否是迭代器對象
print(isinstance('abc',Iterator))
print(isinstance('[1,2,3]',Iterator))
print(isinstance('{"server":"192.168.1.10"}',Iterator))
#生成器確定是迭代器
print(isinstance((x for x in range(10)), Iterator))
print(isinstance(100,Iterator))
 
 
2、裝飾器
定義:
裝飾器本質是函數,用來裝飾其餘函數,爲其餘函數添加函數功能
原則:
1 不能修改被裝飾的函數的源代碼
2 不能修改被裝飾的函數的調用方式
實現裝飾器知識儲備:
1 函數即「變量"
2 高階函數
 a 把一個函數當作實參傳給另一個函數(不修改源代碼狀況下添加功能)
 b 返回值中包含函數名(不修改函數的調用方式)
3 嵌套函數
舉例:
qt.py
#!/usr/bin/env python
#Author is wspikh
# -*- coding: encoding -*-
def foo():
    print("in the foo")
    def bar():
     print("in the bar")
    bar()
foo()
4 高階函數+嵌套函數=》裝飾器
gj.py
#!/usr/bin/env python
#Author is wspikh
# -*- coding: encoding -*-
import time
def bar():
    time.sleep(4)
    print('in the bar')
def test1(func):
    #print(func)
    start_time = time.time()
    func() #run bar
    stop_time = time.time()
    print("the fund run time is %s" %(start_time-stop_time))
#不能寫成test1(bar()),由於bar()表明函數返回值
test1(bar)
 
裝飾器.py
#!/usr/bin/env python
#Author is wspikh
# -*- coding: encoding -*-
import time
#嵌套函數和高階函數的融合
def timer(func):
    def deco():
        start_time=time.time()
        #return func()
        func()
        stop_time=time.time()
        print("the func run time is %s" %(start_time-stop_time))
    return deco #返回值中包含函數名(不修改函數的調用方式)//?

@timer #語法堂 test1=timer(test1)之因此仍是用test1作變量是由於裝飾器不改變被裝飾函數的調用方式,
def test1():
    time.sleep(3)
    print("in the test1")

@timer #語法堂 test2=timer(test2)
def test2():
    time.sleep(3)
    print("in the test2")

test1()
test2()
 
 
3、Json & pickle 數據序列化
定義:
咱們把變量從內存中變成可存儲或傳輸的過程稱之爲序列化。反過來,把變量內容從序列化的對象從新讀到內存裏稱之爲反序列化,即unpickling。
特色:
1 序列化以後,就能夠把序列化後的內容寫入磁盤,或者經過網絡傳輸到別的機器上,在python中提供了兩個模塊可進行序列化。分別是pickle和json。
2 pickle是python中獨有的序列化模塊,所謂獨有,就是指不能和其餘編程語言的序列化進行交互,由於pickle將數據對象轉化爲bytes。pickle模塊提供了四個功能:dumps、dump、loads、load。dumps和dump都是進行序列化,而loads和load則是反序列化。
3 若是咱們要在不一樣的編程語言之間傳遞對象,就必須把對象序列化爲標準格式,好比XML,但更好的方法是序列化爲JSON,由於JSON表示出來就是一個字符串,能夠被全部語言讀取,也能夠方便地存儲到磁盤或者經過網絡傳輸。JSON不只是標準格式,而且比XML更快,並且能夠直接在Web頁面中讀取,很是方便。
4 json中的方法和pickle中差很少,也是dumps,dump,loads,load。使用上也沒有什麼區別,區別在於,json中的序列化後格式爲字符。
5 dumps將所傳入的變量的值序列化爲一個bytes,而後,就能夠將這個bytes寫入磁盤或者進行傳輸。dump則更加一步到位,在dump中能夠傳入兩個參數,一個爲須要序列化的變量,另外一個爲須要寫入的文件。loads當咱們要把對象從磁盤讀到內存時,能夠先把內容讀到一個bytes,而後用loads方法反序列化出對象,也能夠直接用load方法直接反序列化一個文件。
舉例:
序列化和反序列化.py
#!/usr/bin/env python
#Author is wspikh
# -*- coding: encoding -*-
#import json
import pickle

def sayhi(name):
    print("hello",name)

sayhi("alex")

info = {
'age':22,
'name':'alex',
'func':sayhi
}
f = open("json.txt","wb")
#f.write(str(info))
f.write(pickle.dumps(info))
f.close()
#反序列化
f = open("json.txt","rb")
data = pickle.loads(f.read())
print(data)
f.close()
 
 
4、軟件目錄結構規範
目的:
軟件目錄層次清晰,可讀性強。
舉例:
假設你的項目名爲foo, 目錄結構建議以下:
Foo/
|-- bin/ | |-- foo | |-- foo/ | |-- tests/ | | |-- __init__.py | | |-- test_main.py | | | |-- __init__.py | |-- main.py | |-- docs/ | |-- conf.py | |-- abc.rst | |-- setup.py |-- requirements.txt |-- README

簡要解釋:算法

  1. bin/: 存放項目的一些可執行文件,固然你能夠起名script/之類的也行。
  2. foo/: 存放項目的全部源代碼。(1) 源代碼中的全部模塊、包都應該放在此目錄。不要置於頂層目錄。(2) 其子目錄tests/存放單元測試代碼; (3) 程序的入口最好命名爲main.py
  3. docs/: 存放一些文檔。
  4. setup.py: 安裝、部署、打包的腳本。
  5. requirements.txt: 存放軟件依賴的外部Python包列表。
  6. README: 項目說明文件。
相關文章
相關標籤/搜索