溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Python元類與迭代器生成器的示例分析

發(fā)布時(shí)間:2021-08-31 10:29:02 來(lái)源:億速云 閱讀:119 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹Python元類與迭代器生成器的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

1.__getattr__和__getattribute__魔法函數(shù)

__getattr__是當(dāng)類調(diào)用一個(gè)不存在的屬性時(shí)才會(huì)調(diào)用getattr魔法函數(shù),他傳入的值item就是你這個(gè)調(diào)用的不存在的值。
__getattribute__則是無(wú)條件的優(yōu)先執(zhí)行,所以如果不是特殊情況最好不要用__getattribute__。

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

    def __getattr__(self, item):
        return self.info[item]

ls = User("李四",{"gender":"male"})
print(ls.gender)

2.屬性描述符

屬性描述符介紹
屬性描述符是一個(gè)強(qiáng)大的通用協(xié)議。它是properties, methods, static methods, class methods 和super()的調(diào)用原理。

屬性描述符協(xié)議
屬性描述符是實(shí)現(xiàn)了特定協(xié)議的類,只要實(shí)現(xiàn)了__get__,__set__和__delete__三個(gè)方法中的任意一個(gè),這個(gè)類就是描述符,它能實(shí)現(xiàn)對(duì)多個(gè)屬性運(yùn)用相同存取邏輯的一種方式,通俗來(lái)說(shuō)就是:創(chuàng)建一個(gè)實(shí)例,作為另一個(gè)類的類屬性。

注意

? 如果一個(gè)對(duì)象同時(shí)定義了__get__和__set__方法,它被稱做數(shù)據(jù)描述符(data descriptor)。

? 只定義__get__方法的對(duì)象則被稱為非數(shù)據(jù)描述符(non-data descriptor)。

使用類方法創(chuàng)建描述符

? 定義一個(gè)IntField類為描述符類

? 創(chuàng)建IntField類的實(shí)例,作為另一個(gè)User類的屬性

class IntField(object):
    def __set__(self, instance, value):
        print("__set__")

    def __get__(self, instance, owner):
        print("__get__")

    def __delete__(self, instance):
        print("__delete__")


class User(object):
    age = IntField()


ls = User()
ls.age         
ls.age = 30     
del ls.age

使用屬性類型創(chuàng)建描述符

除了使用類當(dāng)作一個(gè)屬性描述符,我們之前學(xué)習(xí)的 property(),就是可以輕松地為任意屬性創(chuàng)建可用的描述符。創(chuàng)建 property() 的語(yǔ)法是 property(fget=None, fset=None, fdel=None, doc=None)

描述符查找順序

? 當(dāng)為數(shù)據(jù)描述符時(shí), __get__優(yōu)先級(jí)高于__dict__
? 當(dāng)為非數(shù)據(jù)描述符時(shí),__dict__優(yōu)先級(jí)高于__get__

元類

元類介紹

元類實(shí)際上就是創(chuàng)建類的類

實(shí)現(xiàn)如下:

? 定義創(chuàng)建類的函數(shù)create_class
? 如果給create_class傳的參數(shù)為user,則創(chuàng)建User類

type()創(chuàng)建元類

? 第一個(gè)參數(shù):name表示類名稱,字符串類型
? 第二個(gè)參數(shù):bases表示繼承對(duì)象(父類),元組類型,單元素使用逗號(hào)
? 第三個(gè)參數(shù):attr表示屬性,這里可以填寫類屬性、類方式、靜態(tài)方法,采用字典格式,key為屬性名,value為屬性值

def __init__(self, name):
    self.name = name
    print("i am __init__")
    
    
User = type("User", (), {"age":18 , "__init__":__init__})
obj = User("amy")       
print(obj.name)

metaclass屬性

如果一個(gè)類中定義了__metalass__ = xxx,Python就會(huì)用元類的方式來(lái)創(chuàng)建類,就可以控制類的創(chuàng)建行為
比如,以下代碼,再不改變類屬性的抒寫情況下,將屬性名規(guī)定為大寫訪問(wèn)。

class MyClass(object):
    name = "ls"
mc = MyClass()
print(mc.name)

Python迭代器

迭代器指的是迭代取值的工具,迭代是指一個(gè)重復(fù)的過(guò)程,每一次重復(fù)都是基于上一次結(jié)果而來(lái)
迭代提供了一種通用的不依賴索引的迭代取值方式

可迭代對(duì)象

可以用for循環(huán)遍歷的對(duì)象都是可迭代對(duì)象。
? str,list,tuple,dict,set等都是可迭代對(duì)象。
? generator,包括生成器和帶yield的生成器函數(shù)。

判斷是否可迭代

除了看內(nèi)置是否含有__iter__方法來(lái)判斷該對(duì)象是否是一個(gè)可迭代的對(duì)象之外,我們還可以使用 isinstance() 判斷一個(gè)對(duì)象是否是 Iterable 對(duì)象
? isinstance()–>用來(lái)判斷對(duì)象是否是相應(yīng)類型,與type()類似。

from collections import Iterable,Iterator
print(isinstance('abc',Iterable))   # True
print(isinstance([1,2,3,4],Iterable))   # True
print(isinstance(123,Iterable))     # False

迭代器對(duì)象

? 有內(nèi)置的__next__()方法的對(duì)象,執(zhí)行該方法可以不依賴索引取值
? 有內(nèi)置的__iter__()方法的對(duì)象,執(zhí)行迭代器的__iter__()方法得到的依然是迭代器本身
需要注意的是,可迭代對(duì)象不一定是迭代器

iter()

可以被next()函數(shù)調(diào)用并不斷返回下一個(gè)值的對(duì)象稱為迭代器:Iterator。
那我們可以通過(guò)iter()方法將可迭代的對(duì)象,轉(zhuǎn)為迭代器。

li = [1,2,3,4]
lis = iter(li)
print(type(lis))    # <class 'list_iterator'>

注意:
? 迭代器不可以通過(guò)下標(biāo)取值,而是使用__next__()或者next()。但是只要超出范圍則直接報(bào)錯(cuò)StopIteration。

print(lis[0])    # 報(bào)錯(cuò) not subscriptable
print(lis.__next__())
print(lis.__next__())
print(lis.__next__())
print(lis.__next__())
print(next(lis))
print(next(lis))
print(next(lis))
print(next(lis))

? next()只能順延調(diào)用,不能往前。

可迭代對(duì)象與迭代器區(qū)別
? 可用于for循環(huán)的都是可迭代類型
? 作用于next()都是迭代器類型
? list、dict、str等都是可迭代的但不是迭代器,因?yàn)閚ext()函數(shù)無(wú)法調(diào)用它們??梢酝ㄟ^(guò)iter()函數(shù)將它們轉(zhuǎn)為迭代器
? python的for循環(huán)本質(zhì)就是通過(guò)不斷調(diào)用next()函數(shù)實(shí)現(xiàn)的

生成器

生成器定義
在Python中,一邊循環(huán)一邊計(jì)算的機(jī)制,稱為生成器:generator。
為什么要有生成器
列表所有數(shù)據(jù)都在內(nèi)存中,如果有海量數(shù)據(jù)的話會(huì)非常消耗內(nèi)存。
比如說(shuō):我們僅僅需要訪問(wèn)前面幾個(gè)元素,但后面絕大多元素占用的內(nèi)存就會(huì)浪費(fèi)了。
那么生成器就是在循環(huán)的過(guò)程中根據(jù)算法不斷推算出后續(xù)的元素,這樣就不用創(chuàng)建整個(gè)完整的列表,從而節(jié)省大量的空間。
總而言之,就是當(dāng)我們想要使用龐大數(shù)據(jù),又想讓它占用的空間少,那就使用生成器。

如何創(chuàng)建生成器

生成器表達(dá)式
生成器表達(dá)式來(lái)源于迭代和列表解析的組合,生成器和列表解析類似,但是它使用()而不是[]。

g = (x for x in range(5))
print(g)       # generator object
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
# 超出報(bào)錯(cuò)
print(next(g))
for i in g:
    print(i)

生成器函數(shù)
當(dāng)一個(gè)函數(shù)中包含yield關(guān)鍵字,那么這個(gè)函數(shù)就不再是一個(gè)普通的函數(shù),而是一個(gè)generator。調(diào)用函數(shù)就是創(chuàng)建了一個(gè)生成器對(duì)象。其工作原理就是通過(guò)重復(fù)調(diào)用next()或者_(dá)_next__()方法,直到捕獲一個(gè)異常。
比如:
實(shí)現(xiàn)斐波那契數(shù)列,除第一個(gè)和第二個(gè)數(shù)外,任何一個(gè)數(shù)都可以由前兩個(gè)相加得到:
1,1,2,3,5,8,12,21,34…

def createNums():
    print("-----func start-----")
    a,b = 0,1
    for i in range(5):
        # print(b)
        print("--1--")
        yield b
        print("--2--")
        a,b = b,a+b
        print("--3--")
    print("-----func end-----")
    
g = createNums()
print(next(g))  
print(next(g))  
print(next(g))
print(next(g))
print(next(g))

注意:

? yield返回一個(gè)值,并且記住這個(gè)返回值的位置,下次遇到next()調(diào)用時(shí),代碼從yield的下一條語(yǔ)句開(kāi)始執(zhí)行。與return的差別是,return也是返回一個(gè)值,但是直接結(jié)束函數(shù)。

迭代器與生成器

? 生成器能做到迭代器能做的所有事

? 而且因?yàn)樯善髯詣?dòng)創(chuàng)建了iter()和next()方法,生成器顯得簡(jiǎn)潔,而且高效。

讀取大文件

文件300G,文件比較特殊,一行 分隔符 {|}

def readlines(f,newline):
    buf = ""
    while True:
        while newline in buf:
            pos = buf.index(newline)
            yield buf[:pos]
            buf = buf[pos + len(newline):]
        chunk = f.read(4096*10)
        if not chunk:
            yield buf
            break
        buf += chunk
with open('demo.txt') as f:
    for line in readlines(f,"{|}"):
        print(line)

以上是“Python元類與迭代器生成器的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI