[英]Python dictionary - dict.get() return value if dict value is None
[英]dict.get(None) on a dict with None value takes default arg
我試圖概括這種情況:
def func(t):
# code which doesn't accept None's
def foo(a):
if a in ('', None):
return None
return func(a)
def foo_b(a):
if a in ('', None):
return None
elif a == 'b'
return 0
return func(a)
我試圖解決它的方法是定義一個字典:
defaults = {None: None, '': None}
def foo(a):
return defaults.get(a, func(a))
def foo_b(a):
defaults_b = {'bar': 0, **defaults}
return defaults_b.get(a, func(a))
運行腳本時:
foo_b(None)
它到達get
方法,從defaults
字典中獲取None
並使用None
進入func()
方法,我得到錯誤,因為func()
方法不排除None
的
用python解決這個問題的最佳實踐是什么?
這是行不通的,因為函數的所有參數都在調用函數之前進行了評估。 所以當你寫
defaults.get(a, func(a))
它首先評估a
和func(a)
,並將兩個結果傳遞給defaults.get()
。 由於func(a)
對a
某些值不起作用,因此在進入defaults.get()
之前會出現錯誤。
一般解決這個問題的方法是默認為一個函數,它只會在必要時被調用。 您需要編寫自己的以這種方式工作的dict.get()
版本。
def dict_get_f(d, key, default_fun):
if key in d:
return d[key]
return default_fun()
然后你可以像這樣使用它:
def foo(a):
return dict_get_f(defaults, a, lambda: func(a))
為什么不直接檢查函數本身?
def func(t):
if t is None:
return None
# go on with the code
正如@Barmar 在他們的回答中指出的那樣,問題不在於dict.get
的行為,而是在調用函數之前評估所有參數的事實,因此defaults.get(a, func(a))
調用func(a)
在它使用該值調用defaults.get
之前。
collections.defaultdict
解決此問題的另一種方法是使用collections.defaultdict
,它提供了一種在值不在字典中時調用函數的方法。
由於您的字典很小,復制它們的成本很低,所以這個解決方案就是這樣做的。
from collections import defaultdict
defaults = {None: None, '': None}
def func(arg):
"""Some function that cannot be called with None"""
if arg is None:
raise ValueError()
print(f'func called with {arg}')
def foo(a):
return defaultdict(lambda: func(a), defaults)[a]
def foo_b(a):
defaults_b = {'bar': 0, **defaults}
return defaultdict(lambda: func(a), defaults_b)[a]
if __name__ == '__main__':
print(foo(None))
print(foo(''))
print(foo(123))
print(foo(123))
print(foo_b(None))
print(foo_b('bar'))
您可以采用的另一種方法是將defaults
字典設為函數字典,並使用lambda: func(a)
的默認值lambda: func(a)
,以避免使用None
調用函數。 因此, defaults.get(a, lambda: func(a))
將返回一個返回正確值的函數,然后您可以調用該函數來獲取您想要的值: defaults.get(a, lambda: func(a))()
.
一個完整的程序:
defaults = {None: (lambda: None), '': (lambda: None)}
def func(arg):
"""Some function that cannot be called with None"""
if arg is None:
raise ValueError()
print(f'func called with {arg}')
def foo(a):
return defaults.get(a, lambda: func(a))()
def foo_b(a):
defaults_b = {'bar': (lambda: 0), **defaults}
return defaults_b.get(a, lambda: func(a))()
if __name__ == '__main__':
print(foo(None))
print(foo(''))
print(foo(123))
print(foo(123))
print(foo_b(None))
print(foo_b('bar'))
作為第三種選擇,您可以使用 Python 中的and
行為,回答您列出的所有默認值都是“假”這一事實( 什么是真假?它與真假有什么不同? )。 在python中, a and b
是短路的,這意味着如果a
為False
或 falsy ,那么它已經知道a and b
不能為True
,因此它返回a
,或者如果a
為真則返回b
。
因此,如果a
是None
,則defaults.get(a, True) and func(a)
等於None and func(a)
。 None
是假的,所以None and func(a)
等於None
。 如果a
不在defaults
則defaults.get(a, True) and func(a)
等於True and func(a)
,它等於func(a)
,因此該函數被調用。
請注意,如果您使用真實的默認值,這將不起作用,例如 if defaults = {None: None, '': None, 'bar': 'something'}
,並且可能難以理解可維護性 - 我只是想我會給另一個選擇。
defaults = {None: None, '': None}
def func(arg):
"""Some function that cannot be called with None"""
if arg is None:
raise ValueError()
print(f'func called with {arg}')
def foo(a):
return defaults.get(a, True) and func(a)
def foo_b(a):
defaults_b = {'bar': 0, **defaults}
return defaults_b.get(a, True) and func(a)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.