python魔法--描述符/property僞裝/協程

什麼是描述符

官方說法:python描述符是一個“綁定行爲”的對象屬性,在描述符協議中,它可以通過方法重寫屬性的訪問。這些方法有 get(), set(), 和__delete__()。如果這些方法中的任何一個被定義在一個對象中,那麼這個對象就是一個描述符。

換句話說: 含有以下三個方法之一的對象就是描述符

三個方法(協議):

get(self, instance, owner):調用一個屬性時,觸發
set(self, instance, value):爲一個屬性賦值時,觸發
delete(self, instance):採用del刪除屬性時,觸發

什麼是self instance、owner?

self 是當前描述符(對象)自身,類似C++this指針, instance 是描述符所屬類對象實體、owner是描述符所在的類(誰擁有這些東西,當然是最高的類)

class Desc(object):
    def __get__(self, instance, owner):
        print("__get__...")
        print("self : \t\t", self)
        print("instance : \t", instance)
        print("owner : \t", owner)
        print('='*40, "\n")     
    def __set__(self, instance, value):
        print('__set__...')
        print("self : \t\t", self)
        print("instance : \t", instance)
        print("value : \t", value)
        print('='*40, "\n")
class TestDesc(object):
    x = Desc()
#以下爲測試代碼
t = TestDesc()
t.x
#以下爲輸出信息:
__get__...
self :          <__main__.Desc object at 0x0000000002B0B828>
instance :      <__main__.TestDesc object at 0x0000000002B0BA20>
owner :      <class '__main__.TestDesc'>
========================================

@property把函數調用僞裝成對屬性的訪問

class Foo:
  @property
  def attr(self):
    print('getting attr')
    return 'attr value'

  def bar(self): pass
foo = Foo()

x = property(get, set, del);

容器類型協議:

如果希望定製的容器不可變:只需要定義 len() getitem()這兩個魔法

如果希望定製的容器可變,還需要定義__setitem__ __delitem __()這兩個魔法

在這裏插入圖片描述

class CountList:
    def __init__(self, *args):
        self.values = [x for x in args]#列表推導式 
        self.count = {}.fromkeys(range(len(self.values)),0)#建立字典記錄訪問次數

    #字典;0 - len(self.value) 
    def __len__(self):
        return len(self.values)

    #獲取值, 並不是獲取訪問次數
    #gwtitem ,只要訪問 必定觸發, 這就是魔法
    def __getitem__(self,key):
        self.count[key] +=1
        return self.values[key]

python 迭代器: iter next

string = ‘hello, python’
it = iter(string)
next(it)
next(it)

iter迭代器爲假的時候,拋出異常
it = iter(“hello,world”)
while True:
try:
each = next(it)
print (each)
except:
break;

迭代器的魔法方法:
iter()
next()

class Iter:
    def __init__(self, n =100):
        self.a = 0
        self.b = 1
        self.n = n

    def __iter__(self):
        return self

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b
        if self.a > self.n:   #停止迭代
            raise StopIteration
        return self.a

在這裏插入圖片描述

生成器 : yeild語句的函數

生成器也是一種迭代器yield 語句返回

亂入 : 胡進裏,沒規律,嘿嘿

協同程序:協程

所謂協同程序就是可以運行的獨立函數調用,函數可以暫停或者掛起,並在需要的時候從程序離開的地方繼續執行

生成器也是一種迭代器,那麼代表它也可以像迭代器一樣, 可以配合next(迭代器對象)使用
在這裏插入圖片描述
在這裏插入圖片描述
仔細觀察: generator 生成器第一次調用之後 yield 返回 ,之後並不是從函數頭再開始 ,而是從離開的地方繼續調用

def generator():
    a = 0
    b = 1
    print("開始迭代生成器")
    while True:
        a,b = b, a+b
        yield a

for each in generator():
    if(each > 100):
        break
    print(each,end = ' ')#不換行 ,以空格代替換行

生成器推導式作爲函數的參數 可以不帶()

eg: 0 + … + 9
本來: sum( (i for i range(10))
和諧掉() sum sum(i for i in range(10))

列表推導式[i for i in range(10)]
字典推導式{i for i in range(100)}
不存在元組推導式哦, 它變成了生成器generator推導式

模塊

容器: 對數據的封裝
函數:對語句的封裝
類 : 方法和屬性的封裝
模塊: 就是程序。

導入模塊名:
Find1 :
導入:import +模塊名(as t)
調用: 模塊名(t). + 函數 ·

name == main

if name == main 作用: 讓python識別: 程序是在主程序運行還是在模塊內運行: 即讓python識別是私有程序還是公有程序

也就是 if name == main 是主程序嗎? 是的話做什麼, 不是的話做什麼

搜索路徑

python 導入模塊的過程有一個路徑搜索的過程

先sys.path.append(“模塊路徑”)
再導入模塊

包 package

第一步 創建一個文件夾存放模塊 。文件見名字就是包的名字
第二步 在文件夾內創建一個__init__.py 的模塊文件,內容可以爲空
第三步 將相關的模塊放在文件夾(包)裏面

導入 : 包名.模塊名

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章