python重要知識(shí)點(diǎn)總結(jié)二

目錄
  • 1、生成器
  • 2、列表解析
  • 3、函數(shù)式編程
  • 4、描述器
  • 5、迭代器

http://coolshell.cn/articles/10822.html

1、生成器

參考學(xué)習(xí)
為什么要使用生成器?很多時(shí)候,通過(guò)列表生成的可迭代對(duì)象占用內(nèi)存會(huì)很大,而且若只是要訪問(wèn)前面幾個(gè)元素,那后面的內(nèi)存空間就會(huì)被浪費(fèi)。若迭代器的構(gòu)建是通過(guò)一個(gè)函數(shù),也就是說(shuō)有規(guī)律的,則可以使用生成器,在循環(huán)的過(guò)程中不斷推算出后續(xù)的元素,這樣就不必創(chuàng)建完整的list,從而節(jié)省大量的空間。

生成器的構(gòu)造方式一
L = [x * x for x in range(10)]
print L
print type(L)

L = (x * x for x in range(10))
print L
print L.next()
print next(L)
print type(L)

for item in L:
    print item

輸出為:

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<type 'list'>
<generator object <genexpr> at 0x027F3A30>
0
1
<type 'generator'>
4
9
16
25
36
49
64
81

上面可以看出,最大的不同就是[]和(),回憶(1,2,3)類型其實(shí)是一個(gè)元祖,元祖的特點(diǎn)就是元素不可變。但為什么這里卻變成了一個(gè)生成器呢,深層次原理不考究,簡(jiǎn)單來(lái)說(shuō)這里包含了元素計(jì)算的算法,生成器保存的實(shí)際上是該算法。注意,生成器也是可迭代對(duì)象,能進(jìn)行for操作。

通過(guò) yield關(guān)鍵字
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1

print type(fib)
print fib(5)
gen = fib(5)
print gen.next()
for item in gen:
    print item

輸出結(jié)果:

<type 'function'>
<generator object fib at 0x01FD3A30>
1
1
2
3
5

如果一個(gè)函數(shù)定義中包含yield關(guān)鍵字,那么這個(gè)函數(shù)就不再是一個(gè)普通函數(shù),而是一個(gè)generator.

generator和函數(shù)的執(zhí)行流程不一樣。函數(shù)是順序執(zhí)行,遇到return語(yǔ)句或者最后一行函數(shù)語(yǔ)句就返回。而變成generator的函數(shù),在每次調(diào)用next()的時(shí)候執(zhí)行,遇到y(tǒng)ield語(yǔ)句返回,再次執(zhí)行時(shí)從上次返回的yield語(yǔ)句處繼續(xù)執(zhí)行。這也隱藏了一個(gè)問(wèn)題,獲取第一個(gè)元素的值也是要通過(guò)next調(diào)用。

生成器還有一些高級(jí)用法,如send()函數(shù)可以向生成器傳入一個(gè)值。更多可以參考generator send

2、列表解析

列表解析式是將一個(gè)列表(實(shí)際上適用于任何可迭代對(duì)象(iterable))轉(zhuǎn)換成另一個(gè)列表的工具。在轉(zhuǎn)換過(guò)程中,可以指定元素必須符合一定的條件,才能添加至新的列表中,這樣每個(gè)元素都可以按需要進(jìn)行轉(zhuǎn)換

new_things = []
for ITEM in old_things:
    if condition_based_on(ITEM):
        new_things.append("something with " + ITEM)

你可以將上面的for循環(huán)改寫成這樣的列表解析式:

new_things = ["something with " + ITEM for ITEM in old_things if condition_based_on(ITEM)]

再例如:

numbers = [1, 2, 3, 4, 5]

doubled_odds = []
for n in numbers:
    if n % 2 == 1:
        doubled_odds.append(n * 2)

轉(zhuǎn)換成了這兩行代碼:

numbers = [1, 2, 3, 4, 5]
doubled_odds = [n * 2 for n in numbers if n % 2 == 1]

上面的其實(shí)也比較簡(jiǎn)單,需要自己有這個(gè)意識(shí)主動(dòng)使用列表解析。而什么時(shí)候需要用到列表解析呢?在創(chuàng)建一個(gè)列表或其他的可迭代對(duì)象時(shí),對(duì)其中的元素需要判斷后再添加進(jìn)去,或者判斷后進(jìn)行適當(dāng)操作再添加,就需要用到列表解析。

再看幾個(gè)其他的列表解析:

循環(huán)嵌套

flattened = []
for row in matrix:
    for n in row:
        flattened.append(n)

可以寫為:

matrix = [(1,2,3),(4,5,6)]
# for row in matrix:
#     for n in row:
#         flattened.append(n)

flattened = [n for row in matrix for n in row]
print flattened

這樣寫是錯(cuò)誤的,flattened = [n for n in row for row in matrix],for循環(huán)的順序和之前的順序是一樣的。

注意可讀性

長(zhǎng)長(zhǎng)的一行讀起來(lái)很費(fèi)力,可適當(dāng)分行如下:

flattened = [
    n
    for row in matrix
    for n in row
]

3、函數(shù)式編程基礎(chǔ) map filter

map

map(function,iterable),對(duì)iterable中每個(gè)元素應(yīng)用function。

version_info = (4, 8)
version = '.'.join(map(str, version_info))

>>> map(lambda x: x + "bzz!",["I think","I'm good"])
['I thinkbzz!', "I'm goodbzz!"]

第一個(gè),返回值是4.8,很簡(jiǎn)單,map將version_info中的整形轉(zhuǎn)換為字符,然后各個(gè)字符之間用‘.’連接。
第二個(gè)要注意,Python2中返回的是一個(gè)列表,而在Python3中是返回可迭代的對(duì)象。
map在一定程度上也可以用列表解析替換如:
[x + 'bzz' for x in ["I think","I'm good"]]

filter

對(duì)所給的可迭代對(duì)象進(jìn)行過(guò)濾

>>> def f(x): return x % 2 != 0 and x % 3 != 0 
>>> filter(f, range(2, 25)) 
[5, 7, 11, 13, 17, 19, 23]
enumerate(iterable[,start])

該函數(shù)返回可迭代的enumerate對(duì)象,生成一個(gè)元組序列,每個(gè)元組包含一個(gè)整形索引(默認(rèn)從0開始,也可以指定start)和迭代對(duì)象中對(duì)應(yīng)的元素。

mylist = ['hello','how','are','you']
for i, item in enumerate(mylist):
    print "Item %d: %s" % (i, item)

輸出為:
Item 0: hello
Item 1: how
Item 2: are
Item 3: you
>>> mylist = [1,2,4]
>>> enumerate(mylist)
<enumerate object at 0x020838C8>
>>> list(enumerate(mylist))
[(0, 1), (1, 2), (2, 4)]
>>>
any(iterable) 和 all(iterable)

主要用來(lái)判斷給定迭代對(duì)象是否滿足相應(yīng)條件,all表示要都滿足,而any表示至少有一個(gè)滿足時(shí)返回真。這兩個(gè)函數(shù)只有一個(gè)輸入,而且是對(duì)每個(gè)元素判斷ture or faulse,因此常常和map函數(shù)配合使用。
等價(jià)于

 def all(iterable):
     for item in iterable:
         if not item:
             return False
     return True

def any(iterable):
    for item in iterable:
        if item:
            return True
    return False
mylist = [0,1,2,3,-2]
print map(lambda x: x > 0, mylist)
if all(map(lambda x: x > 0, mylist)):
    print 'all item grater than 0'
else:
    print 'some less than 0'

輸出為:

[False, True, True, True, False]
some less than 0
zip(iter1 [,iter2 [...]])

主要用于將一組鍵和一組值組合成字典。

print zip(['hello','world'],['hi','big'],['nice','night','right'])
[('hello', 'hi', 'nice'), ('world', 'big', 'night')]

該函數(shù)接收多個(gè)序列并將它們組合成元組,值得注意的是木桶效應(yīng),生成的列表(Python2中返回列表,3中為迭代對(duì)象)取決于最短的輸入序列長(zhǎng)度。

4、描述符

參考學(xué)習(xí)

一個(gè)描述符就是一個(gè)對(duì)象,該對(duì)象代表了一個(gè)屬性的值。這就意味著如果一個(gè)賬戶對(duì)象有一個(gè)屬性“name”,那么描述符就是另一個(gè)能夠用來(lái)代表屬性“name”持有值的對(duì)象。描述符協(xié)議中“定義了__get__”、“__set__”或”__delete__” 這些特殊方法,描述符是實(shí)現(xiàn)其中一個(gè)或多個(gè)方法的對(duì)象。

class Descri(object):
    def __init__(self,name):
        self.name = name

    def __get__(self, instance, owner):
        print '__get__'
        return self.name

    def __set__(self, instance, value):
        print '__set__'
        self.name = value


D = Descri('hello')
D.name = '123'
print D.name
D.name = 'yuan'
print D.name

class Foo(object):
    name = Descri('dodo')

F = Foo()
print F.name
F.name = 'Jiessie'

輸出為:

123
yuan
__get__
dodo
__set__

上面的程序很有意思,為什么直接調(diào)用Descri類沒(méi)有進(jìn)入__get__方法,而下面通過(guò)另一個(gè)類調(diào)用卻會(huì)進(jìn)入。首先要明確什么是描述符,顧名思義,在python中是用來(lái)描述一個(gè)屬性的,一般來(lái)說(shuō),像上面Foo類name屬性,回憶總結(jié)一中,當(dāng)實(shí)例化后,在類的外面是可以隨便修改屬性值的,而描述符會(huì)對(duì)它所代表的類的屬性執(zhí)行類型檢查等自定義操作,這也是描述符存在的價(jià)值。

當(dāng)訪問(wèn)類Foo實(shí)例的任何屬性時(shí),描述符會(huì)調(diào)用它的__get__方法。需要注意的是,__get__方法的第一個(gè)參數(shù)是描述符代表的屬性被引用的源對(duì)象。當(dāng)屬性被分配時(shí),描述符會(huì)調(diào)用它的__set__方法。當(dāng)沒(méi)有定義__set__方法時(shí)就是只讀變量。

描述符可以用來(lái)對(duì)變量值進(jìn)行檢查,但相對(duì)繁瑣,提供了另一種相對(duì)簡(jiǎn)潔方式,property(fget=None, fset=None, fdel=None, doc=None) ,然后實(shí)現(xiàn)相關(guān)函數(shù)即可。
很容易想到property修飾符也表示了同樣的工作,并且更簡(jiǎn)潔,因此,主要用@property這種方式,但描述符需要理解。

5、迭代器

可以直接作用于for循環(huán)的對(duì)象統(tǒng)稱為可迭代對(duì)象Iterable。有以下幾種:
一類是集合數(shù)據(jù)類型,如list、tuple、dict、set、str等;
一類是generator,包括生成器和帶yield的generator function。
由之前知道,生成器不但可以作用于for循環(huán),還可以被next()函數(shù)不斷調(diào)用并返回下一個(gè)值,直到最后拋出StopIteration錯(cuò)誤表示無(wú)法繼續(xù)返回下一個(gè)值了。
于是,迭代器就是可以被next()函數(shù)調(diào)用并不斷返回下一個(gè)值的對(duì)象。要分清楚可迭代對(duì)象和迭代器。

from collections import Iterable,Iterator

print isinstance([],Iterable)
print isinstance((),Iterable)
print isinstance({},Iterable)


print isinstance([],Iterator)
print isinstance((),Iterator)
print isinstance({},Iterator)

print isinstance((x*x for x in range(2,5)),Iterator)

輸出為:

True
True
True
False
False
False
True
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容