国产chinesehdxxxx野外,国产av无码专区亚洲av琪琪,播放男人添女人下边视频,成人国产精品一区二区免费看,chinese丰满人妻videos

8.18 利用Mixins擴展類功能

2018-02-24 15:26 更新

問題

你有很多有用的方法,想使用它們來擴展其他類的功能。但是這些類并沒有任何繼承的關系。因此你不能簡單的將這些方法放入一個基類,然后被其他類繼承。

解決方案

通常當你想自定義類的時候會碰上這些問題??赡苁悄硞€庫提供了一些基礎類,你可以利用它們來構造你自己的類。

假設你想擴展映射對象,給它們添加日志、唯一性設置、類型檢查等等功能。下面是一些混入類:

class LoggedMappingMixin:
    """
    Add logging to get/set/delete operations for debugging.
    """
    __slots__ = ()  # 混入類都沒有實例變量,因為直接實例化混入類沒有任何意義

    def __getitem__(self, key):
        print('Getting ' + str(key))
        return super().__getitem__(key)

    def __setitem__(self, key, value):
        print('Setting {} = {!r}'.format(key, value))
        return super().__setitem__(key, value)

    def __delitem__(self, key):
        print('Deleting ' + str(key))
        return super().__delitem__(key)

class SetOnceMappingMixin:
    '''
    Only allow a key to be set once.
    '''
    __slots__ = ()

    def __setitem__(self, key, value):
        if key in self:
            raise KeyError(str(key) + ' already set')
        return super().__setitem__(key, value)

class StringKeysMappingMixin:
    '''
    Restrict keys to strings only
    '''
    __slots__ = ()

    def __setitem__(self, key, value):
        if not isinstance(key, str):
            raise TypeError('keys must be strings')
        return super().__setitem__(key, value)

這些類單獨使用起來沒有任何意義,事實上如果你去實例化任何一個類,除了產生異常外沒任何作用。它們是用來通過多繼承來和其他映射對象混入使用的。例如:

class LoggedDict(LoggedMappingMixin, dict):
    pass

d = LoggedDict()
d['x'] = 23
print(d['x'])
del d['x']

from collections import defaultdict

class SetOnceDefaultDict(SetOnceMappingMixin, defaultdict):
    pass

d = SetOnceDefaultDict(list)
d['x'].append(2)
d['x'].append(3)
# d['x'] = 23  # KeyError: 'x already set'

這個例子中,可以看到混入類跟其他已存在的類(比如dict、defaultdict和OrderedDict)結合起來使用,一個接一個。結合后就能發(fā)揮正常功效了。

討論

混入類在標志庫中很多地方都出現過,通常都是用來像上面那樣擴展某些類的功能。它們也是多繼承的一個主要用途。比如,當你編寫網絡代碼時候,你會經常使用 socketserver 模塊中的 ThreadingMixIn 來給其他網絡相關類增加多線程支持。例如,下面是一個多線程的XML-RPC服務:

from xmlrpc.server import SimpleXMLRPCServer
from socketserver import ThreadingMixIn
class ThreadedXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
    pass

同時在一些大型庫和框架中也會發(fā)現混入類的使用,用途同樣是增強已存在的類的功能和一些可選特征。

對于混入類,有幾點需要記住。首先是,混入類不能直接被實例化使用。其次,混入類沒有自己的狀態(tài)信息,也就是說它們并沒有定義 __init__() 方法,并且沒有實例屬性。這也是為什么我們在上面明確定義了 __slots__ = () 。

還有一種實現混入類的方式就是使用類裝飾器,如下所示:

def LoggedMapping(cls):
    """第二種方式:使用類裝飾器"""
    cls_getitem = cls.__getitem__
    cls_setitem = cls.__setitem__
    cls_delitem = cls.__delitem__

    def __getitem__(self, key):
        print('Getting ' + str(key))
        return cls_getitem(self, key)

    def __setitem__(self, key, value):
        print('Setting {} = {!r}'.format(key, value))
        return cls_setitem(self, key, value)

    def __delitem__(self, key):
        print('Deleting ' + str(key))
        return cls_delitem(self, key)

    cls.__getitem__ = __getitem__
    cls.__setitem__ = __setitem__
    cls.__delitem__ = __delitem__
    return cls

@LoggedMapping
class LoggedDict(dict):
    pass

這個效果跟之前的是一樣的,而且不再需要使用多繼承了。參考9.12小節(jié)獲取更多類裝飾器的信息,參考8.13小節(jié)查看更多混入類和類裝飾器的例子。

以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號