2013-01-10 62 views
28

我使用urllib.urlencode來構建Web POST參數,但是如果存在除None之外的其他值,我只希望添加一些值。只有在符合條件時才添加字典

apple = 'green' 
orange = 'orange' 
params = urllib.urlencode({ 
    'apple': apple, 
    'orange': orange 
}) 

這工作正常,但是如果我做orange變量可選的,我怎麼能阻止它被添加到參數?事情是這樣的(僞):

apple = 'green' 
orange = None 
params = urllib.urlencode({ 
    'apple': apple, 
    if orange: 'orange': orange 
}) 

我希望這是不夠清楚,沒有人知道如何解決此問題?

+0

如果有一個可以接受的默認值,那麼可以使用橙色:橙色,如果橙色的默認語法。 – jpm

回答

29

你必須單獨添加鍵,創建後的初始dict

params = {'apple': apple} 
if orange is not None: 
    params['orange'] = orange 
params = urllib.urlencode(params) 

Python有沒有語法定義鍵條件;如果你已經擁有一個序列中的所有東西,你可以使用詞典理解:

params = urllib.urlencode({k: v for k, v in (('orange', orange), ('apple', apple)) if v is not None}) 

但這不是很可讀。

+1

輕微:如果可能存在non-None值爲false-ish,則其行爲會有所不同,如0. – DSM

+0

@DSM:OP使用'if orange:'作爲示例,因此我將其基於此。仔細閱讀,我發現確實不是None是必需的。我已經更新了答案。 –

3

您可以分配後清除無:

apple = 'green' 
orange = None 
dictparams = { 
    'apple': apple, 
    'orange': orange 
} 
for k in dictparams.keys(): 
    if not dictparams[k]: 
     del dictparams[k] 
params = urllib.urlencode(dictparams) 
+1

等價地,'d = {k:v for k,v in d.items()if v}' –

+4

這也將清除評估爲False的值。 你應該''如果dictparams [k]是None'。 – PhilipGarnero

0
fruits = [("apple", get_apple()), ("orange", get_orange()), ...] 

params = urllib.urlencode({ fruit: val for fruit, val in fruits if val is not None }) 
1

另一種有效的答案是,你可以創建你自己不存儲無值類似字典的容器。

class MyDict: 
    def __init__(self): 
     self.container = {} 
    def __getitem__(self, key): 
     return self.container[key] 
    def __setitem__(self, key, value): 
     if value != None: 
      self.container[key] = value 
    def __repr__(self): 
     return self.container.__repr__() 

a = MyDict() 
a['orange'] = 'orange'; 
a['lemon'] = None 

print a 

產量:

{'orange': 'orange'} 
16

捎帶上sqreept的回答,下面是表現爲所需的dict一個子類:

class DictNoNone(dict): 
    def __setitem__(self, key, value): 
     if key in self or value is not None: 
      dict.__setitem__(self, key, value) 


d = DictNoNone() 
d["foo"] = None 
assert "foo" not in d 

這將允許現有的密鑰的值是改變None,但將None分配給不存在的密鑰是無操作的。如果你想設置的項目None從詞典中刪除它,如果它已經存在,你可以這樣做:如果您在施工期間通過他們在None可以得到

def __setitem__(self, key, value): 
    if value is None: 
     if key in self: 
      del self[key] 
    else: 
     dict.__setitem__(self, key, value) 

值。如果你想避免這種情況,添加一個__init__方法把它們過濾掉:

def __init__(self, iterable=(), **kwargs): 
    for k, v in iterable: 
     if v is not None: self[k] = v 
    for k, v in kwargs.iteritems(): 
     if v is not None: self[k] = v 

你也可以使它通用寫,所以你可以傳中所需的條件生成字典時:

class DictConditional(dict): 
    def __init__(self, cond=lambda x: x is not None): 
     self.cond = cond 
    def __setitem__(self, key, value): 
     if key in self or self.cond(value): 
      dict.__setitem__(self, key, value) 

d = DictConditional(lambda x: x != 0) 
d["foo"] = 0 # should not create key 
assert "foo" not in d 
+0

更好的例子:) – sqreept

+0

你怎麼能把這個句柄d.update(foo = None)? –

+0

編寫一個新的'.update'方法。 – kindall

9

很老的問題,但這裏是一個替代方案,使用這樣一個事實,即用空字典更新字典什麼也不做。

def urlencode_func(apple, orange=None): 
    kwargs = locals().items() 
    params = dict() 
    for key, value in kwargs: 
     params.update({} if value is None else {key: value}) 
    return urllib.urlencode(params) 
+0

哦,非常整潔。我喜歡這個答案最好! – RCross

相關問題