刻意練習Python基礎 ——day 16:魔法方法(下)

17天 —— Python基礎刻意練習

Day 01——Task01:變量、運算符與數據類型
Day 02——Task02:條件與循環
Day 03——Task03:列表與元組(上)
Day 04——Task03:列表與元組(下)
Day 05——Task04:字符串與序列
Day 06——Task05:函數與Lambda表達式(上)
Day 07——Task05:函數與Lambda表達式(下)
Day 08——Task06:字典與集合
Day 09——Task07:文件與文件系統(上)
Day 10——Task07:文件與文件系統(下)
Day 11——Task08:異常處理
Day 12——Task09:else 與 with 語句
Day 13——Task10:類與對象(上)
Day 14——Task10:類與對象(下)
Day 15——Task11:魔法方法(上)
Day 16——Task11:魔法方法(下)
Day 17——Task12:模塊
    



魔法方法



2.魔法方法


 2.6. 屬性訪問

  __getattr____getattribute____setattr____delattr__

  __getattr__(self, name): 定義當用戶試圖獲取一個不存在的屬性時的行爲。

  __getattribute__(self, name):定義當該類的屬性被訪問時的行爲(先調用該方法,查看是否存在該屬性,若不存在,接着去調用__getattr__)。

  __setattr__(self, name, value):定義當一個屬性被設置時的行爲。

  __delattr__(self, name):定義當一個屬性被刪除時的行爲。

class C:
    def __getattribute__(self, item):
        print('__getattribute__')
        return super().__getattribute__(item)

    def __getattr__(self, item):
        print('__getattr__')

    def __setattr__(self, key, value):
        print('__setattr__')
        super().__setattr__(key, value)

    def __delattr__(self, item):
        print('__delattr__')
        super().__delattr__(item)


c = C()
c.x
# __getattribute__
# __getattr__

c.x = 1
# __setattr__

del c.x
# __delattr__

 2.7. 描述符

  描述符就是將某種特殊類型的類的實例指派給另一個類的屬性。

  • __get__(self, instance, owner)用於訪問屬性,它返回屬性的值。
  • __set__(self, instance, value)將在屬性分配操作中調用,不返回任何內容。
  • __del__(self, instance)控制刪除操作,不返回任何內容。
class MyDecriptor:
    def __get__(self, instance, owner):
        print('__get__', self, instance, owner)

    def __set__(self, instance, value):
        print('__set__', self, instance, value)

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


class Test:
    x = MyDecriptor()


t = Test()
t.x
# __get__ <__main__.MyDecriptor object at 0x000000CEAAEB6B00> <__main__.Test object at 0x000000CEABDC0898> <class '__main__.Test'>

t.x = 'x-man'
# __set__ <__main__.MyDecriptor object at 0x00000023687C6B00> <__main__.Test object at 0x00000023696B0940> x-man

del t.x
# __delete__ <__main__.MyDecriptor object at 0x000000EC9B160A90> <__main__.Test object at 0x000000EC9B160B38>



 2.8. 定製序列

  協議(Protocols)與其它編程語言中的接口很相似,它規定你哪些方法必須要定義。然而,在 Python 中的協議就顯得不那麼正式。事實上,在 Python 中,協議更像是一種指南。

容器類型的協議

  如果說你希望定製的容器是不可變的話,你只需要定義__len__()__getitem__()方法。
  如果你希望定製的容器是可變的話,除了__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)

    def __len__(self):
        return len(self.values)

    def __getitem__(self, item):
        self.count[item] += 1
        return self.values[item]


c1 = CountList(1, 3, 5, 7, 9)
c2 = CountList(2, 4, 6, 8, 10)
print(c1[1])  # 3
print(c2[2])  # 6
print(c1[1] + c2[1])  # 7

print(c1.count)
# {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}

print(c2.count)
# {0: 0, 1: 1, 2: 1, 3: 0, 4: 0}
  • __len__(self)定義當被len()調用時的行爲(返回容器中元素的個數)。
  • __getitem(self, key)定義獲取容器中元素的行爲,相當於self[key]
  • __setitem(self, key, value)定義設置容器中指定元素的行爲,相當於self[key] = value
  • __delitem(self, key)定義刪除容器中指定元素的行爲,相當於del self[key]
    編寫一個可改變的自定義列表,要求記錄列表中每個元素被訪問的次數。
class CountList:
    def __init__(self, *args):
        self.values = [x for x in args]
        self.count = {}.fromkeys(range(len(self.values)), 0)

    def __len__(self):
        return len(self.values)

    def __getitem__(self, item):
        self.count[item] += 1
        return self.values[item]

    def __setitem__(self, key, value):
        self.values[key] = value

    def __delitem__(self, key):
        del self.values[key]
        for i in range(0, len(self.values)):
            if i >= key:
                self.count[i] = self.count[i + 1]
        self.count.pop(len(self.values))


c1 = CountList(1, 3, 5, 7, 9)
c2 = CountList(2, 4, 6, 8, 10)
print(c1[1])  # 3
print(c2[2])  # 6
c2[2] = 12
print(c1[1] + c2[2])  # 15
print(c1.count)
# {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
print(c2.count)
# {0: 0, 1: 0, 2: 2, 3: 0, 4: 0}
del c1[1]
print(c1.count)
# {0: 0, 1: 0, 2: 0, 3: 0}



 2.9. 迭代器

  • 迭代是 Python 最強大的功能之一,是訪問集合元素的一種方式。
  • 迭代器是一個可以記住遍歷的位置的對象。
  • 迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。
  • 迭代器只能往前不會後退。
  • 字符串,列表或元組對象都可用於創建迭代器

  舉一個栗子~

string = 'lsgogroup'
for c in string:
    print(c)

'''
l
s
g
o
g
r
o
u
p
'''

for c in iter(string):
    print(c)


  再來個栗子~


links = {'B': '百度', 'A': '阿里', 'T': '騰訊'}
for each in links:
    print('%s -> %s' % (each, links[each]))
    
'''
B -> 百度
A -> 阿里
T -> 騰訊
'''

for each in iter(links):
    print('%s -> %s' % (each, links[each]))


  • 迭代器有兩個基本的方法:iter()next()
  • iter(object) 函數用來生成迭代器。
  • next(iterator[, default]) 返回迭代器的下一個項目。
  • iterator – 可迭代對象
  • default – 可選,用於設置在沒有下一個元素時返回該默認值,如果不設置,又沒有下一個元素則會觸發 StopIteration 異常。
links = {'B': '百度', 'A': '阿里', 'T': '騰訊'}
it = iter(links)
print(next(it))  # B
print(next(it))  # A
print(next(it))  # T
print(next(it))  # StopIteration


it = iter(links)
while True:
    try:
        each = next(it)
    except StopIteration:
        break
    print(each)

# B
# A
# T


  把一個類作爲一個迭代器使用需要在類中實現兩個魔法方法 __iter__()__next__()

  • __iter__(self)定義當迭代容器中的元素的行爲,返回一個特殊的迭代器對象, 這個迭代器對象實現了 __next__() 方法並通過 StopIteration 異常標識迭代的完成。
  • __next__() 返回下一個迭代器對象。
  • StopIteration 異常用於標識迭代的完成,防止出現無限循環的情況,在__next__() 方法中我們可以設置在完成指定循環次數後觸發 StopIteration 異常來結束迭代。
class Fibs:
    def __init__(self, n=10):
        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


fibs = Fibs(100)
for each in fibs:
    print(each, end=' ')

# 1 1 2 3 5 8 13 21 34 55 89



 2.10. 生成器

  • 在 Python 中,使用了 yield 的函數被稱爲生成器(generator)。
  • 跟普通函數不同的是,生成器是一個返回迭代器的函數,只能用於迭代操作,更簡單點理解生成器就是一個迭代器。
  • 在調用生成器運行的過程中,每次遇到 yield 時函數會暫停並保存當前所有的運行信息,返回 yield 的值, 並在下一次執行 next() 方法時從當前位置繼續運行。
  • 調用一個生成器函數,返回的是一個迭代器對象。
def myGen():
    print('生成器執行!')
    yield 1
    yield 2


myG = myGen()
print(next(myG))  
# 生成器執行!
# 1

print(next(myG))  # 2
print(next(myG))  # StopIteration

myG = myGen()
for each in myG:
    print(each)

'''
生成器執行!
1
2
'''

  用生成器實現斐波那契數列。

def libs(n):
    a = 0
    b = 1
    while True:
        a, b = b, a + b
        if a > n:
            return
        yield a


for each in libs(100):
    print(each, end=' ')

# 1 1 2 3 5 8 13 21 34 55 89



 2.11. 推導式

  列表推導式

a = [i for i in range(100) if (i % 2) != 0 and (i % 3) == 0]
print(a)
# [3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 81, 87, 93, 99]

  字典推導式

b = {i: i % 2 == 0 for i in range(10) if i % 3 == 0}
print(b)
# {0: True, 3: False, 6: True, 9: False}

  集合推導式

c = {i for i in [1, 2, 3, 4, 5, 5, 6, 4, 3, 2, 1]}
print(c)
# {1, 2, 3, 4, 5, 6}

  其它

d = 'i for i in "I Love Lsgogroup"'
print(d)
# i for i in "I Love Lsgogroup"

e = (i for i in range(10))
print(e)
# <generator object <genexpr> at 0x0000007A0B8D01B0>

print(next(e))  # 0
print(next(e))  # 1

for each in e:
    print(each, end=' ')

# 2 3 4 5 6 7 8 9

s = sum([i for i in range(101)])
print(s)  # 5050
s = sum((i for i in range(101)))
print(s)  # 5050






參考資料

  • https://blog.csdn.net/LSGO_MYP/article/details/102887712
  • https://www.runoob.com/python3/python3-tutorial.html
  • https://www.bilibili.com/video/av4050443
  • http://c.biancheng.net/view/2371.html
  • https://www.cnblogs.com/seablog/p/7173107.html
  • https://www.cnblogs.com/Jimmy1988/p/6804095.html
  • https://blog.csdn.net/johnsonguo/article/details/585193
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章