Python高級(jí)編程技巧之Python元類之迭代器生成器2020-07-11

__ getattr __ 和 __ getattribute __ 魔法函數(shù)

  • __ getattr __ :是當(dāng)傳入的值不存在的時(shí)候才會(huì)調(diào)用getattr魔法方法,傳入的值item就是你這個(gè)不存在的值
class User(object):
    def __init__(self, name, info):
        self.name = name
        self.info = info

    def __getattr__(self, item):

        return self.info[item]


u = User('zhangsan', {'age': 18})

print(u.age) 
  • __ getattribute __:無條件優(yōu)先執(zhí)行,所以不是特殊請(qǐng)款不要使用 __ getattribute __


    image.png

屬性描述符

介紹

屬性描述符是一個(gè)通用協(xié)議。他是properties、class methods、static methods、super()的調(diào)用原理

屬性描述符協(xié)議

屬性描述符是實(shí)現(xiàn)特定類的協(xié)議,只要實(shí)現(xiàn)了 __ set __ __ get __ __ delete __其中一個(gè)就是屬性描述符,他能實(shí)現(xiàn)對(duì)多個(gè)屬性運(yùn)用相同的存取邏輯的方式,簡(jiǎn)而言之一個(gè)類的實(shí)例是另一個(gè)類的屬性

  • 注意
    • 一個(gè)類中定義了__ set __ 和 __ get __ 方法稱作數(shù)據(jù)描述符
    • 一個(gè)類中只定義了 __ get __ 方法稱作非數(shù)據(jù)描述符

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

  • 定義一個(gè)IntField類為描述符類
  • 創(chuàng)建IntField類的實(shí)例,作為另一個(gè)User類的屬性
class IntField(object):

    def __set__(self, instance, value):
        print('i am set')

    def __get__(self, instance, owner):
        print('i am get')

class User(object):

    IF = IntField()

u = User()
u.age = 30
print(u.age)

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

除了使用類方法創(chuàng)建屬性描述符,我們還可以使用屬性類型property()創(chuàng)建描述符。語法是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
  • 如果傳入的是user就創(chuàng)建User類

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

  • 第一個(gè)參數(shù):name表示類名,字符串類型
  • 第二個(gè)參數(shù):bases表示繼承對(duì)象,元組類型
  • 第三個(gè)參數(shù):attr表示屬性,可以是類屬性、類方法、靜態(tài)方法,字典格式
def __init__(self, name):
    self.name = name

User = type('User', (), {'age':18, '__init__':__init__})
obj = User('zhangsan')
print(obj.name)

metaclass屬性

  • 如果一個(gè)類中定義了 __ metaclass __ = xxx 屬性,Python就會(huì)用元類的方式創(chuàng)建類,控制類的創(chuàng)建行為
    例如已下代碼,在不改變類屬性書寫情況下,將屬性名規(guī)定大寫訪問
class Myclass(object):
    name = 'ls'
mc = Myclass()
print(mc.name)
# 2.創(chuàng)建upper_attr函數(shù)
def upper_attr(cls_name, cls_parents, cls_attr):
    # print(cls_name)         # MyClass
    # print(cls_parents)      # (<class 'object'>,)
    # print(cls_attr)         # {'__module__': '__main__', '__qualname__': 'MyClass', 'name': 'ls'}
    """
    4.將屬性名規(guī)定為大寫訪問
    - 遍歷取出屬性
    - 如果屬性是非_開頭的
    - 將其轉(zhuǎn)為大寫
    """
    new_attr = {}
    for name, value in cls_attr.items():
        # print(name)
        # print(value)
        if not name.startswith("_"):
            new_attr[name.upper()] = value.upper()

    # 5.返回type創(chuàng)建的類
    return type(cls_name, cls_parents, new_attr)

    # # 3.返回type創(chuàng)建的類
    # return type(cls_name, cls_parents, cls_attr)

# 1.創(chuàng)建MyClass類,指定metaclass=upper_attr
class MyClass(object, metaclass=upper_attr):
    name = "ls"

mc = MyClass()
print(mc.NAME)  

Python迭代器

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

可迭代對(duì)象

可以用for循環(huán)遍歷的都是可迭代對(duì)象

  • str list tuple dict set都是可迭代對(duì)象
  • generator,生成器包括帶yield的生成器函數(shù)

判斷是否可以迭代

除了看內(nèi)置是否含有 __ iter __方法來判斷該對(duì)象是否是一個(gè)可迭代對(duì)象以外,還可以用isinstance()判斷一個(gè)對(duì)象是否是iterable對(duì)象

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í)行該方法得到的仍是迭代器對(duì)象
    需要注意的是可迭代對(duì)象,不一定是迭代器

iter()

  • 可以被next()調(diào)用,并不斷返回下一個(gè)值的對(duì)象叫做迭代器:Iterator
    那我們可以通過iter方法將可迭代對(duì)象轉(zhuǎn)換成迭代器
li = [1,2,3,4]
lis = iter(li)
print(type(lis))    # <class 'list_iterator'>

注意迭代器不可以用下表取值,而是使用__ next __()或者next()超出范圍就會(huì)報(bào)錯(cuò)

可迭代對(duì)象與迭代器的區(qū)別

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

生成器

定義

在Python中一邊循環(huán)一邊計(jì)算的機(jī)制稱為生成器:generator

為什么要有生成器

列表中所有數(shù)據(jù)都在內(nèi)存中,如果有海量數(shù)據(jù)就會(huì)占用非常多的內(nèi)存,如果我們只需要前幾個(gè)元素,如果將所有元素都掉出來就會(huì)非常消耗內(nèi)存

生成器就是在循環(huán)過程中根據(jù)算法不斷推算后面的元素,這樣不用創(chuàng)建整個(gè)完整的列表,比較節(jié)省空間。

總而言之,如果我們想要使用龐大的數(shù)據(jù),又要節(jié)省空間,就可以使用生成器。

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

生成器表達(dá)式

生成器表達(dá)式來自于迭代器和列表解析的結(jié)合,生成器和列表解析類似,但是它使用()而不是[]

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è)generator。調(diào)用函數(shù)就是創(chuàng)建一個(gè)生成器對(duì)象。其工作原理就是重復(fù)調(diào)用next()或者 __ 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))

迭代器與生成器

  • 生成器能做到迭代器能做的所有事
  • 而且因?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)
?著作權(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ù)。

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