簡體   English   中英

用於輪詢字典的Pythonic方法 - 一旦存在,就使用密鑰的值

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM