Python,Day4 - Python基礎4

1、裝飾器

裝飾器本質是函數,裝飾其他函數,就是爲其他函數添加附加功能。

原則:1.不能修改被裝飾的函數的源代碼

    2.不能修改被裝飾的函數的調用方式

 

實現裝飾器 知識儲備

1.函數即“變量”

2.高階函數

        a.把一個函數當作實參傳給另外一個函數(在不修改被裝飾函數源代碼的情況下 爲其添加功能)

        b.返回值中包含函數名(不修改函數的調用方式)

3.嵌套函數

 

高階函數+嵌套函數 = 裝飾器

 

高階函數#變量可以指向函數,函數的參數能接收變量,那麼一個函數就可以接收另一個函數作爲參數,這種函數就稱之爲高階函數。
嵌套函數:在一個函數體內創建另外一個函數,這種函數就叫內嵌函數(基於python支持靜態嵌套域)


知識回顧

 高階函數

def bar():
    print ("in the bar")
def foo(func):
    res=func()
    return res
foo(bar)
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author:DCCimport 
import time
def bar():
    time.sleep(2)
    print("in the bar")
def test1(func):
    start_time=time.time()
    func()
    stop_time=time.time()
    print("run time is %s" %(stop_time-start_time))
test1(bar)


嵌套函數


y = 10
# def test():
#     y+=1
#     print y
def test():    
    # global y
    y = 2    
    print(y)
test()
print(y)
def dad():
    m = 1    
    def son():
        n = 2        
        print('--->', m + n)    
    print('-->',m)
    son()
dad()



注:函數是存在內存中的,只有退出程序後函數才從內存中刪除。如果想刪除內存中的函數,用del


匿名函數

lambda x:x*3
calc = lambda x:x*3
print(calc(3))

運行結果:

9


裝飾器


(1)單獨以f1爲例:

def w1(func):
    def inner():
        # 驗證1
        # 驗證2
        # 驗證3
        return func()
    return inner
 
@w1
def f1():
    print 'f1'

當寫完這段代碼後(函數未被執行、未被執行、未被執行),python解釋器就會從上到下解釋代碼,步驟如下:

  1. def w1(func):  ==>將w1函數加載到內存

  2. @w1

沒錯,從表面上看解釋器僅僅會解釋這兩句代碼,因爲函數在沒有被調用之前其內部代碼不會被執行。

從表面上看解釋器着實會執行這兩句,但是 @w1 這一句代碼裏卻有大文章,@函數名 是python的一種語法糖。

如上例@w1內部會執行一下操作:

  • 執行w1函數,並將 @w1 下面的 函數 作爲w1函數的參數,即:@w1 等價於 w1(f1)
    所以,內部就會去執行:
        def inner:
            #驗證
            return f1()   # func是參數,此時 func 等於 f1
        return inner     # 返回的 inner,inner代表的是函數,非執行函數
    其實就是將原來的 f1 函數塞進另外一個函數中

  • 將執行完的 w1 函數返回值賦值給@w1下面的函數的函數名
    w1函數的返回值是:
       def inner:
            #驗證
            return 原來f1()  # 此處的 f1 表示原來的f1函數
    然後,將此返回值再重新賦值給 f1,即:
    新f1 = def inner:
                #驗證
                return 原來f1() 
    所以,以後業務部門想要執行 f1 函數時,就會執行 新f1 函數,在 新f1 函數內部先執行驗證,再執行原來的f1函數,然後將 原來f1 函數的返回值 返回給了業務調用者。
    如此一來, 即執行了驗證的功能,又執行了原來f1函數的內容,並將原f1函數返回值 返回給業務調用着



(2)問答時間

問題:一個函數可以被多個裝飾器裝飾嗎?

def w1(func):
    def inner(*args,**kwargs):
        # 驗證1
        # 驗證2
        # 驗證3
        return func(*args,**kwargs)
    return inner
 
def w2(func):
    def inner(*args,**kwargs):
        # 驗證1
        # 驗證2
        # 驗證3
        return func(*args,**kwargs)
    return inner
 
 
@w1
@w2
def f1(arg1,arg2,arg3):
    print 'f1'



2、生成器


列表生成式(中括號)

優點:使代碼更簡潔,也可以執行函數

list=[ i*2 for i in range(10)]
print(list)

運行結果

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

注:range默認是從0開始的。


通過列表生成式,我們可以直接創建一個列表。但是,受到內存限制,列表容量肯定是有限的。而且,創建一個包含100萬個元素的列表,不僅佔用很大的存儲空間,如果我們僅僅需要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了。

所以,如果列表元素可以按照某種算法推算出來,那我們是否可以在循環的過程中不斷推算出後續的元素呢?這樣就不必創建完整的list,從而節省大量的空間。在Python中,這種一邊循環一邊計算的機制,稱爲生成器:generator。

要創建一個generator,有很多種方法。第一種方法很簡單,只要把一個列表生成式的[]改成(),就創建了一個generator:

l是一個list[],g是一個generator()

generator保存的是算法,每次調用next(g),就計算出g的下一個元素的值,直到計算到最後一個元素,沒有更多的元素時,拋出StopIteration的錯誤。

#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author:DCC

l = [x * x for x in range(5)]
print(l)
g = (x * x for x in range(5))
print(g)
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))

#運行結果
[0, 1, 4, 9, 16]
<generator object <genexpr> at 0x00000000006969E8>
1
9
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration


小結:生成器與列表的區別

生成器:調用的時候纔會生成

列表:先執行出所有的值



用函數製作生成器

斐波拉契數列:

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

#運行結果
1
3
8
21
55

a, b = b, a + b

相當於

= (b, a + b) # t是一個tuple

= t[0]
= t[1]


******yield 將print(b)改爲yield b,fib函數變成generator
def fib(max):
    n,a,b = 0,0,1
    while n < max:
        #print(b)
        yield  b
        a,b = b,a+b
        n += 1
    return 'done'
print(fib(5))
print(fib(5).__next__())
print(fib(5).__next__())

#運行結果
<generator object fib at 0x000001CDB2D511A8>
1

通過yield實現在單線程的情況下實現併發運算的效果, send的使用

import time
def consumer(name):
    print("%s 準備吃包子啦!" %name)
    while True:
       baozi = yield
       print("包子[%s]來了,被[%s]吃了!" %(baozi,name))
def producer(name):
    c = consumer('A')
    c2 = consumer('B')
    c.__next__()
    c2.__next__()
    print("老子開始準備做包子啦!")
    for i in range(5):
        time.sleep(1)
        print("做了2個包子!")
        c.send(i)
        c2.send(i)
producer("dcc")

#運行結果
A 準備吃包子啦!
B 準備吃包子啦!
老子開始準備做包子啦!
做了2個包子!
包子[0]來了,被[A]吃了!
包子[0]來了,被[B]吃了!
做了2個包子!
包子[1]來了,被[A]吃了!
包子[1]來了,被[B]吃了!
做了2個包子!
包子[2]來了,被[A]吃了!
包子[2]來了,被[B]吃了!
做了2個包子!
包子[3]來了,被[A]吃了!
包子[3]來了,被[B]吃了!
做了2個包子!
包子[4]來了,被[A]吃了!
包子[4]來了,被[B]吃了!

注:

__next__ 只會調用yield

send不僅會調用yield,野會給yield傳個值



3、迭代器

Iterable:可迭代的

Iterator:迭代器

凡是可作用於for循環的對象都是Iterable類型;

凡是可作用於next()函數的對象都是Iterator類型,它們表示一個惰性計算的序列;

簡而言之:

1.可用於for循環的

2.有next方法的就可以成爲迭代器

集合數據類型如listdictstr等是Iterable但不是Iterator,不過可以通過iter()函數獲得一個Iterator對象。

這些可以直接作用於for循環的對象統稱爲可迭代對象:Iterable

可以使用isinstance()判斷一個對象是否是Iterable對象

可以被next()函數調用並不斷返回下一個值的對象稱爲迭代器:Iterator。

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False


生成器都是Iterator對象,但listdictstr雖然是Iterable,卻不是Iterator

listdictstrIterable變成Iterator可以使用iter()函數:

>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True


實例

#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author:DCC

import time

def timer(func):    
    def deco(*args,**kwargs):        
        # def warpper(*args,**kwargs):
        start_time = time.time()
        func(*args,**kwargs)
        stop_time = time.time()        
        print("the func run time is %s" % (stop_time-start_time) )    
    return deco

@timer # test1 = timer(test1)
def test1():
    time.sleep(3)    
    print("in the test1")

@timer # test2 = timer(test2) =deco
def test2(name,age):    
    print(name,age)    
    print("in the test2")

test1()
test2("dcc","2;5")


4、json的簡單實用

json官方說明參見:http://json.org/

Python操作json的標準api庫參考:http://docs.python.org/library/json.html

重要函數

  • 編碼:把一個Python對象編碼轉換成Json字符串   json.dumps()

  • 解碼:把Json格式字符串解碼轉換成Python對象   json.loads()

>>> import json
>>> info = {
    "name":"test",
    "age":"25",
    "sex":"man",
    "type":{"name1":"test1","parameter":["1","2"]}
}
>>> print(type(info))
<class 'dict'>
>>> j = json.dumps(info)
>>> print(j)
{"sex": "man", "type": {"name1": "test1", "parameter": ["1", "2"]}, "age": "25", "name": "test"}
>>> d = json.loads(j)
>>> print(d)
{'age': '25', 'type': {'name1': 'test1', 'parameter': ['1', '2']}, 'sex': 'man', 'name': 'test'}
>>> print(type(d))
<class 'dict'>

sort_keys(對dict對象進行排序,我們知道默認dict是無序存放的)

#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author:DCC

import json
data1 = {'b':789,'c':456,'a':123}
data2 = {'a':123,'b':789,'c':456}
d1 = json.dumps(data1,sort_keys=True)
d2 = json.dumps(data2)
d3 = json.dumps(data2,sort_keys=True)
print(d1)
print(d2)
print(d3)

#運行結果
{"a": 123, "b": 789, "c": 456}
{"b": 789, "a": 123, "c": 456}
{"a": 123, "b": 789, "c": 456}

indent 解碼縮進
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author:DCC

data1 = {'b':789,'c':456,'a':123}
d1 = json.dumps(data1,sort_keys=True,indent=4)
d2 = json.dumps(data1,sort_keys=True)
print(d1)
print(d2)

#運行結果

{
    "a": 123,
    "b": 789,
    "c": 456
}
{"a": 123, "b": 789, "c": 456}

用於序列化的兩個模塊

  • json,用於字符串 和 python數據類型間進行轉換

  • pickle,用於python特有的類型 和 python的數據類型間進行轉換

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

pickle模塊提供了四個功能:dumps、dump、loads、load

wKioL1e2bmLwwO5bAABj47vAqWw979.png-wh_50

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