28 - 生成器交互-__slots__-未實現異常

1 生成器交互

生成器提供了一個send方法用於動態的和生成器對象進行交互。怎麼理解的呢?看下面的例子:python

def generator():
    a = 0
    while True:
        position = yield a   # 格式
        if position:
            a = position
        a += 1

g = generator()
print(next(g))
g.send(10)
print(next(g))
print(next(g))

        上面的 變量 = yield 返回值,是生成器提供的交互格式,當咱們使用生成器對象的send方法時,實參就會被傳遞給這裏的position變量,從而在函數外部來控制函數內部的運行,同時send和next同樣能夠推進生成器的運行。dom

import time
import random
class Person:

    def __init__(self, name):
        self.name = name

    def eat(self):
        while True:
            something = yield
            print('{} is eating {}'.format(self.name, something))


daxin = Person('daxin')
g = daxin.eat()
next(g)

count = 0
while True:
    time.sleep(random.randrange(3))
    g.send('包子-{}'.format(count))
    count += 1

這個例子看起來很雞肋,可是想一下,若是count以上的代碼在另外一個線程中,是否是就實現了不一樣線程之間的切換?函數

2 slots

        字典爲了提高查詢效率,必須用空間換時間。通常來講一個實例,屬性多一點,都存儲在字典中便於查詢,問題不大,可是若是數百萬個實例,那麼字典佔用的空間就很大了,那麼是否能夠把類的__dict__屬性省了?__slots__就是幹這個事情的。線程

class A:
    def __init__(self):
        self.name = 'daxin'
        self.age  = 20
        self.country = 'China'
        self.language = 'Chinese'
        ... ...
a = A()

        實例化對象時,它的屬性信息都會存放在實例本身的__dict__字典中去,因爲沒辦法固定實例的屬性個數,因此這個字典就會很大。好比__dict__申請了300間客房,而只有4個客人住,而且每一個實例都是這樣。當使用了__slots__時code

class A:

    __slots__ = ['name','age']

    def __init__(self):
        self.name = 'daxin'
        self.age  = 20

    def say(self):
        pass

    def hello(self):
        pass


a = A()
a.name = 'tom'
a.sex = 'Man'  # 沒法設置,由於__slots__沒有容許
print(a.__class__.__dict__)  # {'__module__': '__main__', '__slots__': ['name', 'age'], '__init__': <function A.__init__ at 0x0000022422379950>, 'say': <function A.say at 0x00000224223799D8>, 'hello': <function A.hello at 0x0000022422379A60>, 'age': <member 'age' of 'A' objects>, 'name': <member 'name' of 'A' objects>, '__doc__': None}

當類使用了__slots__屬性時:orm

  1. 實例的屬性被__slots__約束,包括在__init__函數中使用self設置的屬性。
  2. 實例的__dict__是在實例化時由__new__方法構建的,當設置了__slots__屬性時,__new__方法不會爲實例建立__dict__屬性字典
  3. 父類的__slots__對應着子類屬性名稱(列表或元組)。
  4. 另外還存在屬性名稱對應的 對象,能夠理解爲類描述器東西。
  5. __slots__只約束實例的屬性,並不約束實例的方法(實例沒有方法,實例是被綁定在類中定義的方法上的)。
  6. 訪問實例屬性時,會被映射到對應的類的描述器上(數據描述器),其內部爲每一個實例構建了專門的對象存儲。(具體實現是用偏移地址來記錄描述器,經過公式能夠直接計算出其在內存中的實際地址,經過直接訪問內存得到。)htm

    定義了__slots__時,指定的屬性都變爲了描述器。對象

        換句話說:__slots__告訴解釋器,實例的屬性都叫什麼,通常來講,既然要節約內存,最好仍是使用元組比較好,一旦類提供了__slots__,就阻止實例產生__dict__來保存實例的屬性。__slots__不影響子類,不會被繼承,但若是父類沒有實現__slots__方法,那麼子類的就沒法生效.blog

        使用建議:爲了正確使用__slots__,最好直接繼承object。若有須要用到其餘父類,則父類和子類都要定義__slots__,還要記得子類的__slots__會覆蓋父類的__slots__。除非全部父類的__slots__都爲空,不然不要使用多繼承。

以上參考自:

https://stackoverflow.com/questions/472000/usage-of-slots
http://code.activestate.com/recipes/532903-how-__slots__-are-implemented/
https://www.cnblogs.com/rainfd/p/slots.html

3 未實現和未實現異常

未實現和未實現的異常是兩個東西他們的含義是:

  • NotImplementedError:未實現異常類,是一個類。
  • NotImplemented:未實現實例,是一個單值。

具體的區別看下面的例子:

class A:

    def __init__(self,x):
        self.data = x

    def __add__(self, other):
        return self.data + other.data

    def __radd__(self, other):
        return other + self.data


a = A(2)
print(1+a)

爲何是3呢。看下面的例子

class A:
    def __init__(self,x):
        self.data = x

    def __add__(self, other):
        try:
            return self.data + other.data
        except:
            return NotImplemented

class B:
    def __init__(self,name):
        self.name = name

    def __radd__(self, other):
        return 'Handsome'

b = A(10)
daxin = B('daxin')

print(b+daxin)  # Handsome

明白了嗎?

  1. b+daxin,其實調用的是b.__add__(daxin)。
  2. 因爲daxin沒有data屬性,因此必定會報異常。可是咱們作了異常捕捉,最後會拋出NotImplemented(未實現)。
  3. 解釋器不找到該值,並不會出發異常,而會轉而調用daxin的__radd__方法。

因此:

  • NotImplementedError通常和raise連用,定義在抽象基類中,用於告訴實例,該方法沒有實現。
  • NotImplemented是個單值,通常在算數方法中告訴解釋器,沒有實現。解釋器轉而執行右邊操做對象的radd方法。

4 Python的對象模型

        在Python中,任何對象都有類型,可使用type()或者__class__查看。可是類型也是對象及類對象,它也有本身的類型。下圖爲Python中的類型與繼承關係:
object
因此新類型的缺省類型都是type(可使用元類來改變)

  • 特殊類型type是全部對象的缺省類型,也包括type本身。但它又是一個對象,所以從object繼承。
  • 特殊類型object是繼承樹的頂層,它是Python全部類型的最終基類。

也就是說:繼承都來自object,類型都看type,type也是對象繼承自object,object也有類型,是type,這倆又很特殊,type的類型是它本身,object沒有基類。

相關文章
相關標籤/搜索