1. 程式人生 > >Python高級用法總結--(列表推導式,叠代器,生成器,裝飾器)

Python高級用法總結--(列表推導式,叠代器,生成器,裝飾器)

方法 叠代器 裝飾 理解 函數調用 循環 一維數組 信息 可叠代對象

列表推導式(list comprehensions)

場景1:將一個三維列表中所有一維數據為a的元素合並,組成新的二維列表。

最簡單的方法:新建列表,遍歷原三維列表,判斷一維數組是否為a,若為a,則將該元素append至新列表中。

缺點:代碼太繁瑣,對於Python而言,執行速度會變慢很多。

針對場景1,我們首先應該想到列表解析式來處理:

lista = [item for item in array if item[0] == ‘a‘]

那麽,什麽是列表解析式?

官方解釋:列表解析式是Python內置的非常簡單卻強大的可以用來創建list的生成式

可以看到,使用列表解析式的寫法更加簡短,除此之外,因為是Python內置的用法,底層使用c語言實現,相較於編寫Python代碼而言,運行速度更快。

場景2:對於一個列表,既要遍歷索引又要遍歷元素

這裏可以使用Python內建函數enumerate,在循環中更好的獲取得到索引

array = [‘I‘, "love‘, ‘Python‘]
for i element in  enumerate(array):
        array[i] = ‘%d:%s‘%(i, element)

可以使用列表推導式對其進行重構

def getitem(index, element):
        return ‘%d:%s‘%(index, element)

array = [‘I‘, ‘love‘, ‘Python‘]

arrayIndex = [getitem(index, element) for indexm element in enumerate(array)]
  

總結:如果要對現有可叠代對象做一下處理,然後生成新的列表,使用列表推導式將是最便捷的方法。

叠代器和生成器

叠代器(Iterator)

這的叠代器可以指for循環,在python中,對於像list,dict和文件等而言,都可以使用for循環,但是它們並不是叠代器,它們屬於可叠代對象。

什麽可叠代對象?

最簡單的解釋:可以使用for...in...語句進行循環的對象,就是可叠代對象(Iterable),可以使用isinstance()方法進行判斷。

from collections import Iterable
type = isinstance(‘python‘, Iterable)
print type

什麽是叠代器?

叠代器指的是可以使用next()方法來回調的對象,可以對可叠代對象使用iter()方法,將其轉換為叠代器。

temp=iter([1, 2, 3])
print type(temp)
print next(temp)

  

此時temp就是一個叠代器,所以說,叠代器基於兩個方法:

  • next:返回下一個項目
  • iter:返回叠代器本身

可以理解為可被next()函數調用並不斷返回下一個值的對象就是叠代器,在定義一個裝飾器時將需要同時定義這兩個方法。

叠代器的優勢

在構建叠代器時,不是將所有元素一次性的加載,而是等調用next方法時返回元素,所有不需要考慮內存的問題。

叠代器應用場景

  • 數列的數據規模巨大
  • 數列有規律,但是不能使用列表推導式描述

生成器

生成器是一種高級叠代器,使得需要返回一系列元素的函數所需的代碼更加的簡單和高效(不像創建叠代器代碼那般冗長)

生成器函數

生成器函數基於yield指令,可以暫停一個函數並返回中間結果。當需要一個將返回一個序列或在循環中執行的函數時,就可以使用生成器,因為當這些元素被傳遞到另一個函數中進行後續處理時,一次返回一個元素可以有效的提升整體性能。

常見的應用場景是使用生成器生成數據流緩沖區

生成器表達式

生成式表達式是一種實現生成器的便捷方式,將列表推導式的中括號替換為圓括號。

和列表推導式的區別:列表生成式可以直接創建一個表,但是生成器表達式是一種邊循環邊計算,使得列表的元素可以在循環過程中一個個的推算出來,不需要創建完整的列表,從而節省了大量的空間。

g = (x*x for x in range(10))

總結:生成器是一種高級叠代器,生成器的優點是延遲計算,一次返回一個結果,這樣非常適用於大數據量的計算。但是,使用生成器必須要註意的一點是:生成器只能遍歷一次。

lambda 表達式(匿名函數)

lambda表達式可以省去定義函數的過程,讓代碼更加的簡潔,適用於簡單函數,編寫處理更大業務的函數需要使用def定義

lambda表達式常用搭配map(), reduce(), filter() 函數使用

  • map():map函數接受兩個參數,一個是函數,一個是序列,其中函數可以接收一個或者多個參數。map將傳入的函數依次作用於序列中的每一個元素,將結果作為新的列表返回。# 將一個列表中的數字轉換為字符串map(str, [1, 2, 3, 4, 5, 6])
  • reduce():函數接收兩個參數,一個是函數,另一個是序列,但是,函數必須接收兩個參數reduce把結果繼續和序列的下一個元素做累積計算,其效果就是reduce(f, [x1, x2l x3, x4]) = f(f(f(x1, x2),x3),x4)
  • filter():該函數用於篩選,將傳入的函數,依次作用於每個元素,然後根據函數的返回值是True還是False,決定是留下還是丟棄該元素

裝飾器

裝飾器本質是一個Python函數,它可以讓其它函數在沒有任何代碼變動的情況下增加額外功能。有了裝飾器,我們可以抽離出大量和函數功能本身無關的雷同代碼並繼續重用。經常用於具有切面需求的場景:包括插入日誌,性能測試,事物處理,緩存和權限校驗等。

場景:計算一個函數的執行時間

一種方法就是定義一個函數,用來專門計算函數的運行時間,然後運行時間計算完成之後再處理真正的業務代碼,代碼如下:

import time
def get_time(func):
      startTime = time.time()
      func()
      endTime = time.time()
      processTime = (endTime - startTime) * 1000
      print "The function timing is %d ms" %processTime

def myfunc():
      print "start func"
      time.sleep(0.8)
      print "end func"

get_time(myfunc)
myfunc()

 

但是這段代碼的邏輯破壞了原有的代碼邏輯,就是對所有func函數的調用都需要使用get_time(func)來實現。

那麽,有沒有更好的展示方式呢?當然有,那就是裝飾器。

編寫簡單的裝飾器

結合上述實例,編寫裝飾器:

def get_time(func):
        def wrapper():
                startTime = time.time()
                func()
                endTime = time.time()
                processTime = (endTime - startTime) * 1000
                print "The function timing is %f ms" %processTime
        return wrapper

print "myfunc is:", myfunc.__name__
myfunc = get_time(myfunc)
print "myfunc is:", myfunc.__name__
myfunc()

 

這樣,一個簡單的完整的裝飾器就實現了,可以看到,裝飾器並沒有影響函數的執行邏輯和調用。在Python中,可以使用“@”語法糖來精簡裝飾器的代碼,將上例更改為:

@get_time
def myfunc():
        print "start func"
        time.sleep(0.8)
        print "end func"

print "myfunc is: ", myfunc.__name__
myfunc()

**裝飾器的調用順序**

裝飾器可以疊加使用,若多個裝飾器同時裝飾一個函數,那麽裝飾器的調用順序和@語法糖的聲明順序相反,也就是:

@decorator1
@decorator2
def func():
        pass

等效於

func = decorator1(decorator2(func()))

被裝飾的函數帶參數

上述實例中,myfunc()是沒有參數的,那如果添加參數的話,裝飾器改如何編寫呢?

#被裝飾的函數帶參數
def get_time3(func):
        def wrapper(*args, **kwargs):
                startTime = time.time()
                func(*args, **kwargs)
                endTime = time.time()
                processTime = (endTime - startTime) * 1000
                print "The function timing is %f ms" %processTime
        return wrapper

@get_time3
def myfunc2(a):
        print "start func"
        print a
        time.sleep(0.8)
        print "end func"

a = "test"
myfunc2(a)

帶參數的裝飾器

裝飾器有很大的靈活性,它本身支持參數,例如在上述實例中,@get_time裝飾器唯一的參數就是執行業務的函數,當然也可以在裝飾器中添加參數,加以邏輯判斷。

內置裝飾器

Python中,常見的類裝飾器包括:@staticmathod、@classmethod、@property

  • @staticmethod:類的靜態方法,跟成員方法的區別是沒有self參數,並且可以在累不進行實例化的情況下調用
  • @classmethod:跟成員方法的區別是接收的第一個參數不是self,而是cls(當前累的具體類型)
  • @property:表示可以直接通過類實例直接訪問的信息。

  

Python高級用法總結--(列表推導式,叠代器,生成器,裝飾器)