在 Python 中,处理缺失值时直接返回 None
并不是一个好的做法。作为一个初学者,我曾经也经常这样做,但后来我意识到这会导致代码中出现难以调试的错误,并且需要额外的检查来确保程序的正常运行。
例如,假设我们有一个字典,我们想从中获取某个键的值。如果该键不存在,直接返回 None
可能会导致后续代码出现问题,因为 None
并不包含任何有用的信息,而且可能会引发异常。
例如,如果我像这样从字典中获取数据:
user_data = {"name": "Kiran", "age": 25}
def get_email(user):
return user.get("email") # This will return None if key is missing
e = get_email(user_data)
print(e.upper()) #AttributeError: 'NoneType' object has no attribute 'upper'
如你所见,我们的程序崩溃了。为了避免这种情况,我们必须使用 if e is not None
检查。这有点恼人。
我们应该采用一些不同的方法来解决这个问题。
1. 尝试使用默认值
如果键不存在,返回一个默认值,而不是 None
。
而不是这样做:
def get_username(user):
if 'name' in user:
return user['name']
return None # This is bad idea
我们可以这么做
def get_username(user):
return user.get('name', "Guest") # It will return a default value
def get_value(data, key, default="Default Value"):
return data.get(key, default)
value = get_value(my_dict, 'some_key', "Key not found")
print(value)
这将返回一个默认值(GUEST)。这将确保我们的程序在尝试使用结果时不会中断。如果我们想顺利运行程序,最好使用这种方法。
但如果缺失的数据显示了需要立即关注的问题,我们也可以引发异常。我们应该始终选择适合自己需要的方法。
如果你想使用默认值,那么请确保它们在你的上下文中是有意义的。
2. 如果 None
出现意外,我们可以引发异常
如果键不存在是一个异常情况,可以选择抛出异常。
不要这样做
def get_price(product):
if 'price' in product:
return product['price']
return None #this is bad approach
我们可以这么做
def get_price(product):
if 'price' not in product:
raise ValueError("Product must have a price!")
return product['price']
我们也可以明确地提出错误。这将迫使调用者正确处理这种情况。
例如,调用者可以像这样捕获异常并进行相应处理:
try:
price = get_price(product)
except ValueError as e:
print(f"Error: {e}") # This will handle missing price properly
3.使用 collections.defaultdict
如果你经常需要处理缺失值,可以使用 collections.defaultdict
,它会为不存在的键提供一个默认值。
from collections import defaultdict
my_dict = defaultdict(lambda: "Default Value")
my_dict['existing_key'] = "Some Value"
print(my_dict['existing_key']) # 输出: Some Value
print(my_dict['non_existing_key']) # 输出: Default Value
4. 使用 Optional
类型提示
如果在某些情况下需要返回 None
,那么至少我们应该使用类型提示来明确说明。
而不是这样做
def find_user(username):
... # Some logic
return None # Hidden None return
我们应该这么做
from typing import Optional
def find_user(username: str) -> Optional[dict]:
... # Some logic
return None # Explicitly stated as an optional return type
现在,如果任何开发人员阅读了这个函数,他/她就会在开始时知道他们需要在这里明确处理 “None”情况。
这也有助于静态分析工具和集成开发环境提供适当的提示和警告。
5. 使用自定义封装类
我们还可以将返回值封装在一个明确表示缺失值的类中
例如:
class Missing:
def __bool__(self):
return False
MISSING = Missing()
def get_email(user):
return user.get('email', MISSING)
email = get_email({})
if not email:
print("No email provided")
我们不必依赖 None, 这种方法会让我们清楚地知道何时缺少一个值。
6. 使用result模式
我们可以为可能失败的函数返回一个结构化的结果......而不是返回None。
例如
from typing import NamedTuple, Union
class Result(NamedTuple):
success: bool
value: Union[str, None]
def get_country(user) -> Result:
if 'country' in user:
return Result(True, user['country'])
return Result(False, None)
result = get_country({})
if not result.success:
print("No country found!")
这种模式可以清楚地说明函数是否成功。
只要这样做......而不是返回None......只要使用这种更好的方法。
希望对你有所帮助。