109

Web POST パラメーターを作成するために使用urllib.urlencodeしていますが、値以外の値が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
})

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

4

12 に答える 12

109

初期を作成した後、キーを個別に追加する必要があります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})

しかし、それはあまり読みにくいです。

Python 3.9 以降を使用している場合は、新しい dict マージ演算子のサポートと条件式を使用できます。

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

しかし、読みやすさが損なわれていることがわかったので、おそらく別のif式を使用するでしょう。

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

別のオプションは、ディクショナリの unpackingを使用することですが、単一のキーの場合はそれほど読みやすくはありません。

params = urllib.urlencode({
    'apple': apple,
    **({'orange': orange} if orange is not None else {})
})

私は個人的にこれを使用することはありません.これはあまりにもハックであり、別のステートメントを使用するほど明確で明確ではありません. Zen of Python が述べているように:if読みやすさは重要です。

于 2013-01-10T17:36:16.217 に答える
39

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ます

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

の値は、構築中に渡すと取得None できます。それを避けたい場合は、__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
于 2013-01-10T17:51:53.507 に答える
6

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

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

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

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

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

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

于 2018-05-13T01:30:45.477 に答える
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)
于 2013-01-10T17:41:15.380 に答える
3

もう 1 つの有効な答えは、 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'}
于 2013-01-10T17:45:27.587 に答える
0
fruits = [("apple", get_apple()), ("orange", get_orange()), ...]

params = urllib.urlencode({ fruit: val for fruit, val in fruits if val is not None })
于 2013-01-10T17:44:15.553 に答える