web-dev-qa-db-ja.com

条件が満たされた場合にのみ辞書に追加します

使っています 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
})

これが十分に明確であったことを願っていますが、誰もこれを解決する方法を知っていますか?

52
user1814016

最初のdictを作成した後、キーを個別に追加する必要があります。

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

Pythonには、キーを条件付きとして定義する構文がありません。シーケンス内のすべてがすでにある場合は、dict内包表記を使用できます。

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

しかし、それはあまり読めません。

45
Martijn Pieters

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を存在しないキーに割り当てることは何もしません。アイテムをNoneremoveに設定したい場合、既に存在する場合は辞書から、これを行うことができます:

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

Nonecanの値は、構築中に渡すと取得されます。それを避けたい場合は、__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

また、辞書を作成するときに、pass in目的の条件を作成できるように記述することで、汎用にすることもできます。

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
28
kindall

かなり古い質問ですが、空のdictでdictを更新しても何も起こらないという事実を使用した代替案です。

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)
13
params = urllib.urlencode({
    'Apple': Apple,
    **({'orange': orange} if orange else {}),
})

割り当て後に[なし]をクリアできます。

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)
3
sqreept

これは私がしました。この助けを願っています。

Apple = 23
orange = 10
a = {
    'Apple' : Apple,
    'orange' if orange else None : orange if orange else None
}

期待される出力:{'orange': 10, 'Apple': 23}

ただし、orange = Noneの場合、None:Noneのエントリは1つになります。たとえば、これを考慮してください:

Apple = 23
orange = None
a = {
    'Apple' : Apple,
    'orange' if orange else None : orange if orange else None
}

期待される出力:{None: None, 'Apple': 23}

2
Nikhil Wagh

別の有効な答えは、None値を格納しない独自のdictのようなコンテナを作成できるということです。

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'}
2
sqreept

私はここの答えのきちんとしたトリックが本当に好きです: https://stackoverflow.com/a/50311983/3124256

しかし、いくつかの落とし穴があります。

  1. ifテストの重複(キーと値について繰り返される)
  2. 結果のdictの厄介なNone: Noneエントリ

これを回避するには、次のことを実行できます。

Apple = 23
orange = None
banana = None
a = {
    'Apple' if Apple else None: Apple,
    'orange' if orange else None : orange,
    'banana' if banana else None: banana,
    None: None,
}
del a[None]

期待される出力:{'Apple': 23}

注:None: Noneエントリは、次の2つのことを保証します。

  1. Noneキーは常に存在します(delはエラーをスローしません)
  2. 'なしの値'の内容は辞書に決して存在しません(後でdelを忘れた場合)

これらのことを心配しない場合は、それを省いてtry...exceptで囲むことができます(またはNoneingの前にdelキーが存在するかどうかを確認します)。代わりに番号2に対処するには、(キーに加えて)値の条件付きチェックを行うこともできます。

0
DylanYoung
fruits = [("Apple", get_Apple()), ("orange", get_orange()), ...]

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