Я недавно узнал о паттерне "объект стража" в python. Я был взят им и начал использовать его везде, где мог. Однако, после того, как я использовал его где-то там, где он не нужен, сотрудник спросил меня об этом. Теперь я не вижу его использования, учитывая, что "x in dict" существует. Вот (усеченный) канонический пример из библиотеки кеша functools LRU:
def _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo):
# Constants shared by all lru cache instances:
sentinel = object() # unique object used to signal cache misses
make_key = _make_key # build a key from the function arguments
PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields
cache = {}
hits = misses = 0
full = False
cache_get = cache.get # bound method to lookup a key or return None
cache_len = cache.__len__ # get cache size without calling len()
lock = RLock() # because linkedlist updates aren't threadsafe
root = [] # root of the circular doubly linked list
root[:] = [root, root, None, None] # initialize by pointing to self
if maxsize == 0:
def wrapper(*args, **kwds):
# No caching -- just a statistics update after a successful call
nonlocal misses
result = user_function(*args, **kwds)
misses += 1
return result
elif maxsize is None:
def wrapper(*args, **kwds):
# Simple caching without ordering or size limit
nonlocal hits, misses
key = make_key(args, kwds, typed)
result = cache_get(key, sentinel)
if result is not sentinel:
hits += 1
return result
result = user_function(*args, **kwds)
cache[key] = result
misses += 1
return result
Теперь просто сосредоточимся на той части, где используется шаблон:
result = cache_get(key, sentinel)
if result is not sentinel:
hits += 1
return result
result = user_function(*args, **kwds)
cache[key] = result
misses += 1
return result
Насколько Я могу сказать, это можно переписать следующим образом:
if key not in cache:
result = user_function(*args, **kwds)
cache[key] = result
misses += 1
else:
result = cache_get(key)
hits += 1
return result
Я задавался вопросом: в чем преимущество этого дозорного метода? Я думал, что это может быть эффективность. Вики python говорят, что "x in s" - это среднее значение O (n), а элемент get - O (1) среднее значение. Но действительно ли это имеет практическую разницу во времени?
Я выполнил несколько быстрых тестов на своем ноутбуке, и время выполнения близко, как в сценарии ios, где большинство ключей являются попаданиями, так и большинство ключей отсутствуют.
В ответ на @martineau Я не думаю, что есть какая-то дополнительная функциональность, которую мы получаем из этого шаблона, как продемонстрировано в этом интерактивном сеансе:
>>> d={1:None}
>>> if 1 in d:
... print('one is there')
...
one is there
>>> if 2 in d:
... print('two is not')
...
>>> d={1:None,None:3}
>>> if None in d:
... print('we can find a none key as well')
...
we can find a none key as well
Итак, остается вопрос: в чем смысл этого шаблона?