如果A vs如果A不是None:

rba*_*ros 136 python

我可以用吗:

if A:
Run Code Online (Sandbox Code Playgroud)

代替

if A is not None:
Run Code Online (Sandbox Code Playgroud)

后者似乎很冗长.有区别吗?

Gre*_*ill 134

该声明

if A:
Run Code Online (Sandbox Code Playgroud)

将调用A.__nonzero__()(请参阅特殊方法名称文档)并使用该函数的返回值.以下是摘要:

object.__nonzero__(self)

被称为实施真值测试和内置操作bool(); 应该返回FalseTrue,或它们的整数等价物01.如果未定义此方法,__len__()则调用此方法(如果已定义),如果其结果为非零,则将该对象视为true.如果一个类既未定义也__len__()未定义__nonzero__(),则其所有实例都被视为真.

另一方面,

if A is not None:
Run Code Online (Sandbox Code Playgroud)

比较参考A,None以查看它是否相同.

  • @gnibbler不是根据我的测试.`if object():pass`每个循环是~0.130 usec,而`if object()不是None:pass`是~0.135 usec.无论如何,你不应该使用性能来在这两者之间进行选择,而应该看看它们如何工作的差异,因为它们不等同*. (35认同)
  • 所以"A不是无"更快,因为工作要少得多 (2认同)
  • @gnibbler `if A is not None` 似乎更慢,因为它是一个比较,需要加载内置的单例 `None` 作为与 `A` 比较的中间步骤(看看 `dis.dis()` )。如果我错了,请纠正我,但只要您真的想测试真值而不是“无”身份,`if A:` 似乎更有效率。 (2认同)
  • @cedbeu,似乎依赖于A的值.我现在测试了`python -m timeit -s"a = 0""如果a:pass""else:pass"`比`python -m timeit -s快" a = 0""如果a是None:pass""else:pass"`但是`python -m timeit -s"a = 1""如果a:pass""else:pass"`慢一点.可能取决于平台,看看你是否得到了相同的结果 (2认同)
  • @cedbeu,在Python3中它们都快得多,但是`None`测试对我来说确实是最慢的.在pypy他们都测量完全一样:) (2认同)

scr*_*esh 47

PEP8所述:

  • None 这样的单例的比较应该总是用'is'或'is not'来完成,而不是等于运算符.

    此外,当你真正意味着"如果x不是无"时,请注意写"if x" - 例如,在测试默认为None的变量或参数是否设置为其他值时.另一个值可能有一个类型(如容器)在布尔上下文中可能为false!

  • 嗯,这不是很清楚,并且不响应OP.自动重定向到PEP并不总是很好的答案.通常,人们对单身"无"的身份测试不感兴趣,而只是在真值检查中.在这种情况下,`如果A:`看起来效率更高(采用`dis.dis()`,还有额外的步骤加载内置的`None`并比较,如果A不是None:`,那么在另一种情况下只是一个`jump_if`). (7认同)

Abd*_*eer 23

if x: #x is treated True except for all empty data types [],{},(),'',0 False, and None
Run Code Online (Sandbox Code Playgroud)

所以它不一样

if x is not None # which works only on None
Run Code Online (Sandbox Code Playgroud)


Kir*_*ser 16

如果没有合适的结果,很多函数都会返回None.例如,.first()如果结果中没有行,则SQLAlchemy查询的方法将返回None.假设您选择的值可能返回0并且需要知道它是否实际为0或者查询是否完全没有结果.

一个常见的习惯用法是给函数或方法的可选参数设置默认值None,然后测试该值为None以查看是否指定了它.例如:

def spam(eggs=None):
    if eggs is None:
        eggs = retrievefromconfigfile()
Run Code Online (Sandbox Code Playgroud)

比较一下:

def spam(eggs=None):
    if not eggs:
        eggs = retrievefromconfigfile()
Run Code Online (Sandbox Code Playgroud)

在后者中,如果你打电话spam(0)或者spam([])怎么办?该函数将(错误地)检测到您没有传入值,eggs并为您计算默认值.这可能不是你想要的.

或者想象一下像"返回给定帐户的交易列表"这样的方法.如果该帐户不存在,则可能返回None.这与返回空列表不同(这意味着"此帐户存在但未记录事务).

最后,回到数据库的东西.NULL和空字符串之间有很大的区别.一个空字符串通常表示"这里有一个值,而这个值根本就没有".NULL表示"尚未输入此值".

在每种情况下,你都想使用if A is None.您正在检查特定值 - 无 - 不仅仅是"任何恰好转换为False的值".


Pit*_*kos 10

他们做了很多不同的事情.

下面的检查是否有不同的价值观什么False,[],None,''0.它检查A 的.

if A:
Run Code Online (Sandbox Code Playgroud)

下面检查A是否是与None不同的对象.它检查并比较A和None 的引用(存储器地址).

if A is not None:
Run Code Online (Sandbox Code Playgroud)

更新:进一步解释

很多时候这两个人似乎做同样的事情,所以很多人互换地使用它们 - 这是一个非常糟糕的主意.由于解释器/编译器的优化(如实习或其他),两者给出相同结果的原因很多次是纯粹的巧合.

考虑到这些优化,相同值的整数和字符串最终使用相同的内存空间.这可能解释了为什么两个单独的字符串就好像它们是相同的.

> a = 'test'
> b = 'test'
> a is b
True
> a == b
True
Run Code Online (Sandbox Code Playgroud)

其他事情的行为并不相同,但..

> a = []
> b = []
> a is b
False
> a == b
True
Run Code Online (Sandbox Code Playgroud)

这两个清单显然有自己的记忆.令人惊讶的是元组表现得像字符串.

> a = ()
> b = ()
> a is b
True
> a == b
True
Run Code Online (Sandbox Code Playgroud)

可能这是因为元组保证不会改变,因此重用相同的内存是有意义的.

这样做的底线是你不能依赖巧合.仅仅因为它像鸭子一样嘎嘎叫它并不意味着它是一只鸭子.使用is==取决于您真正想要检查的内容.这些东西可能很难调试,因为is读起来像散文,我们经常只是略过它.


kef*_*ich 7

如果A:如果A为0,False或None,则证明为假,这可能导致不希望的结果.


Col*_*ill 6

我见过的大多数指南建议你应该使用

如果一个:

除非你有理由更具体.

有一些细微的差别.除了None之外还有返回False的值,例如空列表,或者0,因此请考虑一下您正在测试的内容.


Ben*_*Ben 5

这取决于上下文。

if A:在期望A成为某种集合时使用,并且我只想在集合不为空时执行该块。这允许调用者传递任何行为良好的集合,无论是否为空,并让它按照我的期望执行。它还允许NoneFalse抑制块的执行,这有时方便调用代码。

OTOH,如果我希望A是某个完全任意的对象,但它可能被默认为None,那么我总是使用if A is not None,因为调用代码可能故意传递对空集合、空字符串或 0 值数字类型的引用,或者布尔值False,或在布尔上下文中碰巧为 false 的某个类实例。

另一方面,如果我希望A是一些更具体的东西(例如,我要调用其方法的类的实例),但它可能已被默认为None,并且我认为默认布尔转换是一个类的属性我不介意强制执行所有子类,然后我会用它if A:来节省我的手指输入额外 12 个字符的可怕负担。


mir*_*ngu 5

在Python中none是一个特殊值,通常指定一个未初始化的变量。要测试A是否不具有此特定值,请使用:

if A is not None
Run Code Online (Sandbox Code Playgroud)

Falsey值是Python中的特殊对象类(例如false,[])。要测试A是否为假,请使用:

if not A
Run Code Online (Sandbox Code Playgroud)

因此,这两个表达式并不相同,您最好不要将它们视为同义词。


PS None也是假的,因此第一个表达式表示第二个表达式。但是第二个覆盖了除None之外的其他虚假值。现在...如果您可以确定除了A中的“无”以外,您不能再有其他虚假值,那么可以将第二个表达式替换为第一个表达式。


小智 5

其他答案都给出了很好的信息,但我觉得有必要澄清一下。

不,你不应该使用:

if A:
Run Code Online (Sandbox Code Playgroud)

如果你需要测试的是:

if A is not None:
Run Code Online (Sandbox Code Playgroud)

第一个通常可以替代第二个,但第一个是难以发现错误的常见来源。即使您所做的只是编写一些快速丢弃的代码,您也不应该让自己养成编写有错误的代码的习惯。训练你的手指和大脑来书写和阅读测试的正确详细形式:

if A is not None: 
Run Code Online (Sandbox Code Playgroud)

None 的常见用途是定义可选参数值,并为变量赋予默认起始值​​,这意味着“还没有值”,而函数则意味着“没有返回值”。如果你编写一个函数,例如:

def my_func(a_list, obj=None):
    if obj:          # Trying to test if obj was passed
        a_list.append(obj)
    # do something with a_list
Run Code Online (Sandbox Code Playgroud)

这对于许多现实世界的用途来说效果很好,例如:

my_func(user_names, "bob")
Run Code Online (Sandbox Code Playgroud)

但如果发生以下任何一种情况:

my_func(user_names, "")
my_func(user_names, [])
my_func(user_names, 0)
Run Code Online (Sandbox Code Playgroud)

那么零长度对象将不会被添加到列表中。当编写第一个代码时,您可能知道不允许使用零长度的用户名。所以短代码可以正常工作。但随后您尝试修改代码以使用空字符串来表示类似没有名称的匿名用户之类的内容,突然此函数停止执行预期的操作(将匿名用户添加到列表中)。

例如,假设您有逻辑来定义何时允许用户登录,写法如下:

new_user = get_user_name()

if user_list_ok(my_func(current_users, new_user)):
    # user_list_ok() tests that no more than 10 users can
    # log in at the same time, and that no sigle user can
    # can log in more than 3 times at once.

    # This user is allowed to log in!

    log_user_in(new_user)
Run Code Online (Sandbox Code Playgroud)

现在,这会在您的代码中产生微妙且复杂的错误。“”的匿名用户不会被添加到测试列表中,因此当系统达到10个用户的限制时,测试仍然允许匿名用户登录,从而将用户数推至11。这样可能会触发系统另一部分的错误,该错误要求最多只有 10 个用户。

当您需要测试“var没有值”时,您应该始终使用较长的“is not None”测试,即使它感觉丑陋且冗长。