我什么时候应该使用 None vs False?
When should I use None vs False?
据我所知,None
和 False
唯一一次表现不同是在将它们相互比较时(为了相等)。我是否遗漏了什么,或者只要您的用法一致,就可以只使用一个或另一个吗?有什么理由要用一个而不是另一个吗?
我会在这里强调语义上的差异而不是行为上的差异。
让我们考虑几个函数:
def find_user(criteria):
if is_met(criteria):
return User(...)
return None
# ...vs
def has_email(user):
return bool(user.email)
对我来说,None
背后的语义意味着没有价值,而 False
背后的语义意味着布尔值错误。
这里的类比可以是 C++ 中 bool
类型的演进。当 C (ab) 将 int 用于布尔逻辑时,C++ 引入了一种专用的 bool
类型,这使得某些 variables/function 签名背后的意图更加清晰。它还允许进行一些优化,例如 std::vector<bool>
在内部表示为位向量而不是字节。
如果要检查值是否已分配或存在,可以使用 None
。
dct = {'key':'value'}
x = dct.get('key', None) # Get the value or get`None if it doesn't exist
def func(...):
if condition:
return Object()
return None
而如果您知道该值将存在但想检查它是 属性,请使用 False
if empty_list: #An empty list evaluates to `False`
do something
if not bool_var:
do something
另外 bool(None)
的计算结果为 False
它们是不同的类型。尽管在实践中,它们的行为非常相似。您还可以将 False
替换为:""
、[]
、(,)
或 0
,一切都会正常进行。每当您将变量传递给 if
、while
或任何布尔运算符(例如 or
、and
等)时,Python 会自动将您的变量转换为布尔值或任何需要布尔值的内置函数(旁注:尽管 or
和 and
确实将您的值转换为布尔值,同时决定将什么转换为 return,最终结果将是您未转换的值)。这就是为什么很难区分的原因。
然而,大多数开发者会认为 None
类似于其他语言中的 null
值,这是一个错误或未初始化的值。 Whilist False
通常被认为是一个预期的和完全初始化的值。因此,如果您坚持该约定,大多数人将更容易阅读您的代码。
进一步阐述这一点,让我们考虑 C Python 实现。典型的 if 语句将转换为 POP_JUMP_IF_FALSE
(或 POP_JUMP_IF_TRUE
)指令。这是如何实现的:
TARGET(POP_JUMP_IF_FALSE) {
PyObject *cond = POP();
int err;
if (cond == Py_True) {
Py_DECREF(cond);
FAST_DISPATCH();
}
if (cond == Py_False) {
Py_DECREF(cond);
JUMPTO(oparg);
FAST_DISPATCH();
}
err = PyObject_IsTrue(cond);
Py_DECREF(cond);
if (err > 0)
;
else if (err == 0)
JUMPTO(oparg);
else
goto error;
DISPATCH();
}
如您所见,如果传递给 if
的值是一个布尔值,解释器将立即知道该怎么做。否则,它将调用 PyObject_IsTrue,这将尝试使用任何可能的方式将对象转换为布尔值(__bool__
、__nonzero__
、__len__
,甚至与 None
明确)。
据我所知,None
和 False
唯一一次表现不同是在将它们相互比较时(为了相等)。我是否遗漏了什么,或者只要您的用法一致,就可以只使用一个或另一个吗?有什么理由要用一个而不是另一个吗?
我会在这里强调语义上的差异而不是行为上的差异。
让我们考虑几个函数:
def find_user(criteria):
if is_met(criteria):
return User(...)
return None
# ...vs
def has_email(user):
return bool(user.email)
对我来说,None
背后的语义意味着没有价值,而 False
背后的语义意味着布尔值错误。
这里的类比可以是 C++ 中 bool
类型的演进。当 C (ab) 将 int 用于布尔逻辑时,C++ 引入了一种专用的 bool
类型,这使得某些 variables/function 签名背后的意图更加清晰。它还允许进行一些优化,例如 std::vector<bool>
在内部表示为位向量而不是字节。
如果要检查值是否已分配或存在,可以使用 None
。
dct = {'key':'value'}
x = dct.get('key', None) # Get the value or get`None if it doesn't exist
def func(...):
if condition:
return Object()
return None
而如果您知道该值将存在但想检查它是 属性,请使用 False
if empty_list: #An empty list evaluates to `False`
do something
if not bool_var:
do something
另外 bool(None)
的计算结果为 False
它们是不同的类型。尽管在实践中,它们的行为非常相似。您还可以将 False
替换为:""
、[]
、(,)
或 0
,一切都会正常进行。每当您将变量传递给 if
、while
或任何布尔运算符(例如 or
、and
等)时,Python 会自动将您的变量转换为布尔值或任何需要布尔值的内置函数(旁注:尽管 or
和 and
确实将您的值转换为布尔值,同时决定将什么转换为 return,最终结果将是您未转换的值)。这就是为什么很难区分的原因。
然而,大多数开发者会认为 None
类似于其他语言中的 null
值,这是一个错误或未初始化的值。 Whilist False
通常被认为是一个预期的和完全初始化的值。因此,如果您坚持该约定,大多数人将更容易阅读您的代码。
进一步阐述这一点,让我们考虑 C Python 实现。典型的 if 语句将转换为 POP_JUMP_IF_FALSE
(或 POP_JUMP_IF_TRUE
)指令。这是如何实现的:
TARGET(POP_JUMP_IF_FALSE) {
PyObject *cond = POP();
int err;
if (cond == Py_True) {
Py_DECREF(cond);
FAST_DISPATCH();
}
if (cond == Py_False) {
Py_DECREF(cond);
JUMPTO(oparg);
FAST_DISPATCH();
}
err = PyObject_IsTrue(cond);
Py_DECREF(cond);
if (err > 0)
;
else if (err == 0)
JUMPTO(oparg);
else
goto error;
DISPATCH();
}
如您所见,如果传递给 if
的值是一个布尔值,解释器将立即知道该怎么做。否则,它将调用 PyObject_IsTrue,这将尝试使用任何可能的方式将对象转换为布尔值(__bool__
、__nonzero__
、__len__
,甚至与 None
明确)。