flake8在过滤条件中的布尔比较"=="上发出警告

120

我在 mysql 数据库表中有一个布尔字段。

# table model
class TestCase(Base):
    __tablename__ = 'test_cases'
    ...
    obsoleted = Column('obsoleted',  Boolean)

要获取所有未过时的测试用例数,可以简单地这样做:

caseNum = session.query(TestCase).filter(TestCase.obsoleted == False).count()
print(caseNum)

这样做可以,但是flake8会报出如下警告:

E712: 比较False应该写成"if cond is False:" 或者 "if not cond:"

好的,我认为这有道理。所以把我的代码改成了这样:

caseNum = session.query(TestCase).filter(TestCase.obsoleted is False).count()
或者
caseNum = session.query(TestCase).filter(not TestCase.obsoleted).count()

但是它们都不能起作用。结果始终为0。 我认为筛选条件不支持运算符"is"或"is not"。有人能告诉我如何处理这种情况吗?我不想禁用flake。


PEP 8特别建议避免使用“if cond is False”。我很惊讶pep8工具却相反。 - Janne Karila
6个回答

148
那是因为SQLAlchemy的过滤器是少数几个适合使用== False的地方。在其他任何地方都不应该使用它。在该行代码中添加# noqa注释即可解决问题。或者您可以使用sqlalchemy.sql.expression.false
from sqlalchemy.sql.expression import false

TestCase.obsoleted == false()

当你的会话SQL方言需要正确的值时,false()返回正确的值。这里有一个匹配的sqlalchemy.expression.true


120

1
在Python中,is==是不同的,但我非常确定这里生成的SQL将是相同的。 - avoliva
3
在SQLAlchemy中,is==是不同的,因为你无法覆盖Python中的身份运算符(is)。像Model.column is False这样的表达式总是被计算为False,因为比较总是立即发生在Python中而不是数据库中。将列对象的身份与布尔值进行比较的结果总是为False。这会向查询中插入诸如WHERE FALSEAND FALSE之类的语句,在大多数情况下会导致它返回0行,无论如何。 - Josh
无法与Oracle配合工作。 - Alpensin

24

我查看了使用SQLAlchemy时,当==is_Postgresql数据库方言用于布尔字段时生成的确切查询:

  • 对于==我们得到:

    1. field == False 转换为 field = false
    2. field == True 转换为 field = true
    3. field == None 转换为 field IS NULL
  • 对于is_()我们得到:

    1. field.is_(False) 转换为 field IS false
    2. field.is_(True) 转换为 field IS true
    3. field.is_(None) 转换为 field IS NULL

注意: is_(not None)会被计算为 is_(bool(not None) ,给出is_(True),导致 field = true,所以您最好使用isnot(None)生成field IS NOT NULL


2
请注意,当您在PostgreSQL中使用is而不是=时,即使操作数为NULL,您也永远不会得到NULL作为答案。 如果任何一个操作数为NULL,则=将返回NULL。 - Jim Hunziker

3
为什么不使用 .filter_by(field=True) / .filter_by(field=False)

1
如果你加入了表filter_by,需要注意的一件事是它可能会产生歧义。 - Alex Collins

1
caseNum = session.query(TestCase).filter(~TestCase.obsoleted).count()
print(caseNum)

在你的SQLAlchemy版本中尝试运行它。


1

@Jruv在语句前使用# noqa,它会忽略警告。


5
# noqa 会禁用整个字符串的 flake8/pep/其他代码检查器,因此其他 linting 警告也将被忽略。其他答案提供了更好的解决方案,例如.is_方法。 - maxkoryukov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接