[英]Pythonic way of polling a dictionary - using the key's value once it exists
我有一個解決這個問題的工作方案,它只是感覺不是非常pythonic。 我在Python 2.7中工作,因此不能使用Python 3解決方案。
我有一本定期更新的字典。 最后一個鍵,讓我們稱之為“foo”,一個值將出現在字典中。 我想繼續輪詢該對象並獲取該字典,直到鍵“foo”出現,此時我想獲得與該鍵相關聯的值並使用它。
這是一些現在正在運行的偽代碼:
polled_dict = my_object.get_dict()
while('foo' not in polled_dict.keys()):
polled_dict = my_object.get_dict()
fooValue = polled_dict['foo']
讓我強調一下,代碼現在正在做什么。 感覺很糟糕但是很有效。 我想出的一個潛在的解決方案是:
fooValue = None
While fooValue is None:
polled_dict = my_object.get_dict()
fooValue = polled_dict.get('foo')
這也有效,但它似乎只是更好一點。 一旦它出現在dict中(在while循環期間訪問密鑰並且在退出while循環時再次訪問),我們只調用一次,而不是一次調用polled_dict.get('foo')。 但是,老實說,它似乎並沒有好轉,收益微乎其微。
當我查看我已實現的其他解決方案時,我發現它們只是上述兩個示例的不同邏輯排列(不是在不同的地方或其他地方),但沒有任何感覺pythonic。 我似乎會有一種簡單,清潔的方式來做到這一點。 有什么建議? 如果沒有,上述任何一個都比另一個好嗎?
編輯很多答案都建議我覆蓋或以其他方式更改代碼輪詢的字典。 我同意這通常是一個很好的解決方案,但引用我的一些評論如下:
“有問題的代碼需要與更新字典的API分開存在。這段代碼必須是通用的,並且可以訪問大量不同類型對象的字典。添加觸發器最終需要完全重新處理所有這些對象(並且不會像這個函數那樣通用了)這顯然已經大大簡化了,但是,最終,我需要檢查這個dict中的值,直到它出現而不是觸發對象中的某些東西。我不相信這樣做一個廣泛的,可能具有破壞性的變化是pythonic解決方案(盡管API應該從頭開始重寫,這肯定是解決方案,對於不需要分離/可以訪問API的東西,這絕對是pythonic解決方案。 )”
如果您的對象正在修改字典,那么您只需要獲取一次。 然后你和你的對象有一個指向同一個字典對象的指針。 如果你需要堅持輪詢,那么這可能是最干凈的解決方案:
polled_dict = my_object.get_dict()
while 'foo' not in polled_dict:
pass # optionally sleep
fooValue = polled_dict['foo']
這樣做的最佳總體方法是以某種方式通過管道/套接字/線程鎖推送某種類型的事件。
你總是可以做類似子類dict
事情。
這是完全未經測試的,但有一些影響:
class NoisyDict(dict):
def __init__(self, *args, **kwargs):
self.handlers = {}
#Python 3 style
super().__init__(*args, **kwargs)
def add_handler(self, key, callback):
self.handlers[key] = self.handlers.get(key, [])
self.handlers[key].append(callback)
def __getitem__(self, key):
for handler in self.handlers.get(key, []):
handler('get', key, super().__getitem__(key))
return super().__getitem__(key)
def __setitem__(self, key, value):
for handler in self.handlers.get(key, []):
handler('set', key, value)
return super().__setitem(value)
然后你可以做到
d = NoisyDict()
d.add_handler('spam', print)
d['bar'] = 3
d['spam'] = 'spam spam spam'
發電機的樂趣:
from itertools import repeat
gen_dict = (o.get_dict() for o in repeat(my_object))
foo_value = next(d['foo'] for d in gen_dict if 'foo' in d)
是不是可以做這樣的事情? (顯然不是線程安全的)唯一的問題是下面的方法沒有通過構造捕獲字典初始化。 也就是說,在創建字典時不會捕獲添加的鍵; 例如MyDict(watcher = MyWatcher(),a = 1,b = 2) - a和b鍵不會被添加。 我不確定如何實現它。
class Watcher(object):
"""Watches entries added to a MyDict (dictionary). key_found() is called
when an item is added whose key matches one of elements in keys.
"""
def __init__(self, *keys):
self.keys = keys
def key_found(self, key, value):
print key, value
class MyDict(dict):
def __init__(self, *args, **kwargs):
self.watcher = kwargs.pop('watcher')
super(MyDict, self).__init__(*args, **kwargs)
def __setitem__(self, key, value):
super(MyDict, self).__setitem__(key, value)
if key in self.watcher.keys:
self.watcher.key_found(key, value)
watcher = Watcher('k1', 'k2', 'k3')
d = MyDict(watcher=watcher)
d['a'] = 1
d['b'] = 2
d['k1'] = 'k1 value'
也許Try / Except會被認為更“Pythonic”?
while循環中的sleep語句也會停止消耗所有資源。
polled_dict = my_object.get_dict()
while True:
time.sleep(0.1)
try:
fooValue = polled_dict['foo']
return (foovalue) # ...or break
except KeyError:
polled_dict = my_object.get_dict()
我認為默認情況對於這種工作很有用。
from collections import defaultdict
mydeafultdict = defaultdict(lambda : None)
r = None
while r is None:
r = mydeafultdict['foo']
defaultdict
就像普通字典一樣工作,除非一個鍵不存在,它調用在構造函數中提供給它的函數來返回一個值。 在這種情況下,我給它一個只返回None
的lambda。 有了這個,你可以繼續嘗試獲取foo
,當有一個與之關聯的值時,它將被返回。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.