1.__getattr__和__getattribute__魔法函數(shù)
__getattr__是當(dāng)類調(diào)用一個不存在的屬性時才會調(diào)用getattr魔法函數(shù),他傳入的值item就是你這個調(diào)用的不存在的值。
__getattribute__則是無條件的優(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.屬性描述符
屬性描述符介紹
屬性描述符是一個強(qiáng)大的通用協(xié)議。它是properties, methods, static methods, class methods 和super()的調(diào)用原理。
屬性描述符協(xié)議
屬性描述符是實(shí)現(xiàn)了特定協(xié)議的類,只要實(shí)現(xiàn)了__get__,__set__和__delete__三個方法中的任意一個,這個類就是描述符,它能實(shí)現(xiàn)對多個屬性運(yùn)用相同存取邏輯的一種方式,通俗來說就是:創(chuàng)建一個實(shí)例,作為另一個類的類屬性。
注意
• 如果一個對象同時定義了__get__和__set__方法,它被稱做數(shù)據(jù)描述符(data descriptor)。
• 只定義__get__方法的對象則被稱為非數(shù)據(jù)描述符(non-data descriptor)。
使用類方法創(chuàng)建描述符
• 定義一個IntField類為描述符類
• 創(chuàng)建IntField類的實(shí)例,作為另一個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)作一個屬性描述符,我們之前學(xué)習(xí)的 property(),就是可以輕松地為任意屬性創(chuàng)建可用的描述符。創(chuàng)建 property() 的語法是 property(fget=None, fset=None, fdel=None, doc=None)
描述符查找順序
• 當(dāng)為數(shù)據(jù)描述符時, __get__優(yōu)先級高于__dict__
• 當(dāng)為非數(shù)據(jù)描述符時,__dict__優(yōu)先級高于__get__
元類
元類介紹
元類實(shí)際上就是創(chuàng)建類的類
實(shí)現(xiàn)如下:
• 定義創(chuàng)建類的函數(shù)create_class
• 如果給create_class傳的參數(shù)為user,則創(chuàng)建User類
type()創(chuàng)建元類
• 第一個參數(shù):name表示類名稱,字符串類型
• 第二個參數(shù):bases表示繼承對象(父類),元組類型,單元素使用逗號
• 第三個參數(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屬性
如果一個類中定義了__metalass__ = xxx,Python就會用元類的方式來創(chuàng)建類,就可以控制類的創(chuàng)建行為
比如,以下代碼,再不改變類屬性的抒寫情況下,將屬性名規(guī)定為大寫訪問。
class MyClass(object):
name = "ls"
mc = MyClass()
print(mc.name)
Python迭代器
迭代器指的是迭代取值的工具,迭代是指一個重復(fù)的過程,每一次重復(fù)都是基于上一次結(jié)果而來
迭代提供了一種通用的不依賴索引的迭代取值方式
可迭代對象
可以用for循環(huán)遍歷的對象都是可迭代對象。
• str,list,tuple,dict,set等都是可迭代對象。
• generator,包括生成器和帶yield的生成器函數(shù)。
判斷是否可迭代
除了看內(nèi)置是否含有__iter__方法來判斷該對象是否是一個可迭代的對象之外,我們還可以使用 isinstance() 判斷一個對象是否是 Iterable 對象
• isinstance()–>用來判斷對象是否是相應(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
迭代器對象
• 有內(nèi)置的__next__()方法的對象,執(zhí)行該方法可以不依賴索引取值
• 有內(nèi)置的__iter__()方法的對象,執(zhí)行迭代器的__iter__()方法得到的依然是迭代器本身
需要注意的是,可迭代對象不一定是迭代器
iter()
可以被next()函數(shù)調(diào)用并不斷返回下一個值的對象稱為迭代器:Iterator。
那我們可以通過iter()方法將可迭代的對象,轉(zhuǎn)為迭代器。
li = [1,2,3,4]
lis = iter(li)
print(type(lis)) # class 'list_iterator'>
注意:
• 迭代器不可以通過下標(biāo)取值,而是使用__next__()或者next()。但是只要超出范圍則直接報(bào)錯StopIteration。
print(lis[0]) # 報(bào)錯 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)用,不能往前。
可迭代對象與迭代器區(qū)別
• 可用于for循環(huán)的都是可迭代類型
• 作用于next()都是迭代器類型
• list、dict、str等都是可迭代的但不是迭代器,因?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ù)的話會非常消耗內(nèi)存。
比如說:我們僅僅需要訪問前面幾個元素,但后面絕大多元素占用的內(nèi)存就會浪費(fèi)了。
那么生成器就是在循環(huán)的過程中根據(jù)算法不斷推算出后續(xù)的元素,這樣就不用創(chuàng)建整個完整的列表,從而節(jié)省大量的空間。
總而言之,就是當(dāng)我們想要使用龐大數(shù)據(jù),又想讓它占用的空間少,那就使用生成器。
如何創(chuàng)建生成器
生成器表達(dá)式
生成器表達(dá)式來源于迭代和列表解析的組合,生成器和列表解析類似,但是它使用()而不是[]。
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)錯
print(next(g))
for i in g:
print(i)
生成器函數(shù)
當(dāng)一個函數(shù)中包含yield關(guān)鍵字,那么這個函數(shù)就不再是一個普通的函數(shù),而是一個generator。調(diào)用函數(shù)就是創(chuàng)建了一個生成器對象。其工作原理就是通過重復(fù)調(diào)用next()或者_(dá)_next__()方法,直到捕獲一個異常。
比如:
實(shí)現(xiàn)斐波那契數(shù)列,除第一個和第二個數(shù)外,任何一個數(shù)都可以由前兩個相加得到:
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返回一個值,并且記住這個返回值的位置,下次遇到next()調(diào)用時,代碼從yield的下一條語句開始執(zhí)行。與return的差別是,return也是返回一個值,但是直接結(jié)束函數(shù)。
迭代器與生成器
• 生成器能做到迭代器能做的所有事
• 而且因?yàn)樯善髯詣觿?chuàng)建了iter()和next()方法,生成器顯得簡潔,而且高效。
讀取大文件
文件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)
到此這篇關(guān)于Python元類與迭代器生成器案例詳解的文章就介紹到這了,更多相關(guān)Python元類與迭代器生成器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- Python基礎(chǔ)之元編程知識總結(jié)
- Python中用Decorator來簡化元編程的教程
- Python中使用裝飾器和元編程實(shí)現(xiàn)結(jié)構(gòu)體類實(shí)例
- 簡析Python函數(shù)式編程字符串和元組及函數(shù)分類與高階函數(shù)
- python使用xpath獲取頁面元素的使用
- 如何利用Python批量處理行、列和單元格詳解
- Python BeautifulSoup基本用法詳解(通過標(biāo)簽及class定位元素)
- python中使用 unittest.TestCase單元測試的用例詳解
- Python接口自動化淺析unittest單元測試原理
- python自動化八大定位元素講解
- python一繪制元二次方程曲線的實(shí)例分析
- 詳解Python自動化中這八大元素定位
- python元組打包和解包過程詳解
- 淺談Python的元編程