<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 問題 在創建一個類的對象時,如果之前使用同樣參數創建過這個對象, 你想返回它的緩存引用。 ## 解決方案 這種通常是因為你希望相同參數創建的對象時單例的。在很多庫中都有實際的例子,比如 `logging` 模塊,使用相同的名稱創建的 `logger` 實例永遠只有一個。例如: >>> import logging >>> a = logging.getLogger('foo') >>> b = logging.getLogger('bar') >>> a is b False >>> c = logging.getLogger('foo') >>> a is c True >>> 為了達到這樣的效果,你需要使用一個和類本身分開的工廠函數,例如: # The class in question class Spam: def __init__(self, name): self.name = name # Caching support import weakref _spam_cache = weakref.WeakValueDictionary() def get_spam(name): if name not in _spam_cache: s = Spam(name) _spam_cache[name] = s else: s = _spam_cache[name] return s 然后做一個測試,你會發現跟之前那個日志對象的創建行為是一致的: >>> a = get_spam('foo') >>> b = get_spam('bar') >>> a is b False >>> c = get_spam('foo') >>> a is c True >>> ## 討論 編寫一個工廠函數來修改普通的實例創建行為通常是一個比較簡單的方法。但是我們還能否找到更優雅的解決方案呢? 例如,你可能會考慮重新定義類的 `__new__()` 方法,就像下面這樣: # Note: This code doesn't quite work import weakref class Spam: _spam_cache = weakref.WeakValueDictionary() def __new__(cls, name): if name in cls._spam_cache: return cls._spam_cache[name] else: self = super().__new__(cls) cls._spam_cache[name] = self return self def __init__(self, name): print('Initializing Spam') self.name = name 初看起來好像可以達到預期效果,但是問題是 `__init__()` 每次都會被調用,不管這個實例是否被緩存了。例如: >>> s = Spam('Dave') Initializing Spam >>> t = Spam('Dave') Initializing Spam >>> s is t True >>> 這個或許不是你想要的效果,因此這種方法并不可取。 上面我們使用到了弱引用計數,對于垃圾回收來講是很有幫助的,關于這個我們在8.23小節已經講過了。當我們保持實例緩存時,你可能只想在程序中使用到它們時才保存。一個 `WeakValueDictionary` 實例只會保存那些在其它地方還在被使用的實例。否則的話,只要實例不再被使用了,它就從字典中被移除了。觀察下下面的測試結果: >>> a = get_spam('foo') >>> b = get_spam('bar') >>> c = get_spam('foo') >>> list(_spam_cache) ['foo', 'bar'] >>> del a >>> del c >>> list(_spam_cache) ['bar'] >>> del b >>> list(_spam_cache) [] >>> 對于大部分程序而已,這里代碼已經夠用了。不過還是有一些更高級的實現值得了解下。 首先是這里使用到了一個全局變量,并且工廠函數跟類放在一塊。我們可以通過將緩存代碼放到一個單獨的緩存管理器中: import weakref class CachedSpamManager: def __init__(self): self._cache = weakref.WeakValueDictionary() def get_spam(self, name): if name not in self._cache: s = Spam(name) self._cache[name] = s else: s = self._cache[name] return s def clear(self): self._cache.clear() class Spam: manager = CachedSpamManager() def __init__(self, name): self.name = name def get_spam(name): return Spam.manager.get_spam(name) 這樣的話代碼更清晰,并且也更靈活,我們可以增加更多的緩存管理機制,只需要替代manager即可。 還有一點就是,我們暴露了類的實例化給用戶,用戶很容易去直接實例化這個類,而不是使用工廠方法,如: >>> a = Spam('foo') >>> b = Spam('foo') >>> a is b False >>> 有幾種方式可以防止用戶這樣做,第一個是將類的名字修改為以下劃線(_)開頭,提示用戶別直接調用它。第二種就是讓這個類的 `__init__()` 方法拋出一個異常,讓它不能被初始化: class Spam: def __init__(self, *args, **kwargs): raise RuntimeError("Can't instantiate directly") # Alternate constructor @classmethod def _new(cls, name): self = cls.__new__(cls) self.name = name 然后修改緩存管理器代碼,使用 `Spam._new()` 來創建實例,而不是直接調用 `Spam()` 構造函數: # ------------------------最后的修正方案------------------------ class CachedSpamManager2: def __init__(self): self._cache = weakref.WeakValueDictionary() def get_spam(self, name): if name not in self._cache: temp = Spam3._new(name) # Modified creation self._cache[name] = temp else: temp = self._cache[name] return temp def clear(self): self._cache.clear() class Spam3: def __init__(self, *args, **kwargs): raise RuntimeError("Can't instantiate directly") # Alternate constructor @classmethod def _new(cls, name): self = cls.__new__(cls) self.name = name return self 最后這樣的方案就已經足夠好了。緩存和其他構造模式還可以使用9.13小節中的元類實現的更優雅一點(使用了更高級的技術)。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看