在 Python 中使用“not”布尔运算符

Yuchuan 发表于 2021/11/24 19:59:00 2021/11/24
【摘要】 Pythonnot是一个逻辑运算符,用于反转布尔表达式和对象的真值。当您需要检查条件语句和while循环中未满足的条件时,它很方便。 您可以使用not运算符来帮助您决定程序中的操作过程。您还可以使用它来反转代码中布尔变量的值。

目录

Python 的not运算符允许您反转布尔表达式和对象的真值。您可以在布尔上下文中使用此运算符,例如if语句和while循环。它也适用于非布尔上下文,允许您反转变量的真值。

not有效地使用运算符将帮助您编写准确的负布尔表达式来控制程序中的执行流程。

在本教程中,您将学习:

  • Python 的not运算符如何工作
  • 如何not布尔非布尔上下文中使用运算符
  • 如何使用operator.not_()函数进行逻辑否定
  • 如何以及何时避免代码中不必要的负面逻辑

您还将编写一些实际示例,使您能够更好地理解not运算符的一些主要用例及其使用的最佳实践。要从本教程中获得最大收益,您应该具备一些有关布尔逻辑、条件语句while循环的先前知识。

在 Python 中使用布尔逻辑

George Boole将现在称为Boolean algebra 的东西放在一起,它依赖于truefalse值。它还定义了一组布尔运算:ANDOR,和NOT。这些布尔值和运算符对编程很有帮助,因为它们可以帮助您决定程序中的操作过程。

在Python中,布尔型bool是的子类int

>>>
>>> issubclass(bool, int)
True
>>> help(bool)
Help on class bool in module builtins:

class bool(int)
    bool(x) -> bool
    ...

这种类型有两个可能的值,TrueFalse,它们是Python中的内置常量,必须大写。在内部,Python 将它们实现为整数:

>>>
>>> type(True)
<class 'bool'>
>>> type(False)
<class 'bool'>

>>> isinstance(True, int)
True
>>> isinstance(False, int)
True

>>> int(True)
1
>>> int(False)
0

Python 在内部实现其布尔值1forTrue0for False。继续并True + True交互式shell 中执行以查看会发生什么。

Python 提供了三个布尔或逻辑运算符:

操作员 逻辑运算
and 连词
or 分离
not 否定

使用这些运算符,您可以通过将布尔表达式相互连接、对象相互连接、甚至布尔表达式与对象连接来构建表达式。Python 使用英文单词作为布尔运算符。这些词是语言的关键字,因此您不能将它们用作标识符而不会导致语法错误

在本教程中,您将了解 Python 的not运算符,它实现逻辑NOT运算或否定

Pythonnot运算符入门

not操作是布尔或逻辑运算,实现在Python否定。它是一元的,这意味着它只需要一个操作数。操作数可以是布尔表达式或任何 Python对象。即使是用户定义的对象也能工作。的任务not是反转其操作数的真值

如果您应用not到计算结果为 的操作数True,那么您将得到False结果。如果你申请not一个假操作数,那么你会得到True

>>>
>>> not True
False

>>> not False
True

not运营商否定其操作数的真值。一个真正的操作数返回False。返回一个假操作数True。这两个语句发现了什么是俗称的真值表not

operand not operand
True False
False True

使用not,您可以否定任何布尔表达式或对象的真值。此功能在以下几种情况下值得使用:

  • 在语句和循环的上下文中检查未满足的条件ifwhile
  • 反转对象或表达式的真值
  • 检查一个值是否不在给定的容器中
  • 检查对象的身份

在本教程中,您将找到涵盖所有这些用例的示例。首先,您将首先了解not运算符如何处理布尔表达式以及常见的 Python 对象。

布尔表达式总是返回一个布尔值。在 Python 中,这种表达式返回Trueor False。假设您要检查给定的数字变量是否大于另一个:

>>>
>>> x = 2
>>> y = 5

>>> x > y
False

>>> not x > y
True

表达式x > y总是返回False,所以你可以说它是一个布尔表达式。如果你放在not这个表达式之前,那么你会得到相反的结果,True

注意: Python 根据严格的顺序计算运算符,通常称为运算符优先级

例如,Python 首先计算数学和比较运算符。然后它评估逻辑运算符,包括not

>>>
>>> not True == False
True

>>> False == not True
File "<stdin>", line 1
    False == not True
             ^
SyntaxError: invalid syntax

>>> False == (not True)
True

在第一个示例中,Python 计算表达式True == False,然后通过计算否定结果not

在第二个示例中,Python 首先计算相等运算符 ( ==) 并引发 a ,SyntaxError因为无法比较Falseand not。您可以not True用括号 ( ())将表达式括起来以解决此问题。这个快速更新告诉 Python 首先计算括号中的表达式。

在逻辑运算符中,not比具有相同优先级的and运算符和运算符具有更高的优先or级。

您还可以使用not常见的 Python 对象,例如numbersstringslists、 tuplesdictionariesset、用户定义的对象等:

>>>
>>> # Use "not" with numeric values
>>> not 0
True
>>> not 42
False
>>> not 0.0
True
>>> not 42.0
False
>>> not complex(0, 0)
True
>>> not complex(42, 1)
False

>>> # Use "not" with strings
>>> not ""
True
>>> not "Hello"
False

>>> # Use "not" with other data types
>>> not []
True
>>> not [1, 2, 3]
False
>>> not {}
True
>>> not {"one": 1, "two": 2}
False

在每个示例中,not否定其操作数的真值。为了确定给定对象是真还是假,Python 使用bool(),它返回TrueFalse取决于手头对象的真值。

这个内置函数在内部使用以下规则来计算其输入的真值:

默认情况下,一个对象被认为是真的,除非它的类定义了一个__bool__()返回False__len__()方法或一个返回零的方法,当与对象一起调用时。以下是大多数被认为是 false 的内置对象:

  • 常量定义为 false:NoneFalse.
  • 任何数字类型的零:00.00jDecimal(0),Fraction(0, 1)
  • 空序列和集合:''()[]{}set(),range(0)

来源

一旦not知道其操作数的真值,它就会返回相反的布尔值。如果对象的计算结果为True,则not返回False。否则,它返回True

注意:始终返回True或是与其他两个布尔运算符,运算符和运算符False之间的重要区别。notandor

and运算符和or在表达式中操作数的操作者返回一个,而not操作者总是返回一个布尔值:

>>>
>>> 0 and 42
0
>>> True and False
False
>>> True and 42 > 27
True

>>> 0 or 42
42
>>> True or False
True
>>> False or 42 < 27
False

>>> not 0
True
>>> not 42
False
>>> not True
False

使用and运算符和or运算符,当这些值之一显式地由计算操作数产生时,您可以从表达式中获取TrueFalse返回。否则,您将获得表达式中的操作数之一。另一方面,not行为不同,返回TrueFalse不管它需要的操作数。

为了表现得像and操作符和or操作符,not操作符必须创建并返回新对象,这通常是模棱两可的,并不总是直截了当的。例如,如果表达式 likenot "Hello"返回一个空字符串 ( "") 怎么办?像not ""return这样的表达式会是什么?这就是not操作符总是返回Trueor的原因False

现在您已经了解了notPython 的工作原理,您可以深入研究这个逻辑运算符的更具体的用例。在下一节中,您将学习not布尔上下文中使用

not在布尔上下文中使用运算符

与其他两个逻辑运算符一样,not运算符在布尔上下文中特别有用。在 Python 中,您有两个定义布尔上下文的语句:

  1. if语句让您执行有条件的执行并根据一些初始条件采取不同的行动方案。
  2. while循环允许您在给定条件为真时执行条件迭代并运行重复性任务。

这两个结构是您所谓的控制流语句的一部分。它们帮助您决定程序的执行路径。对于not运算符,您可以使用它来选择在不满足给定条件时要采取的操作。

if 声明

您可以notif语句中使用运算符来检查是否不满足给定条件。if如果某事没有发生,要进行语句测试,您可以将not运算符放在手头的条件前面。由于not运算符返回否定的结果,因此变为真,反之亦然False

if带有not逻辑运算符的语句的语法是:

if not condition:
    # Do something...

在此示例中,condition可以是布尔表达式或任何有意义的 Python 对象。例如,condition可以是包含字符串、列表、字典、集合甚至用户定义对象的变量。

如果condition计算结果为 false,则not返回Trueif运行代码块。如果condition计算结果为真,则not返回False并且if代码块不执行。

一种常见情况是您将谓词布尔值函数用作condition. 假设您想在进行任何进一步处理之前检查给定数字是否为素数。在这种情况下,您可以编写一个is_prime()函数:

>>>
>>> import math

>>> def is_prime(n):
...     if n <= 1:
...         return False
...     for i in range(2, int(math.sqrt(n)) + 1):
...         if n % i == 0:
...             return False
...     return True
...

>>> # Work with prime numbers only
>>> number = 3
>>> if is_prime(number):
...     print(f"{number} is prime")
...
3 is prime

在这个例子中,is_prime()将一个整数作为参数,True如果该数字是素数则返回。否则,它返回False

您还可以在否定条件语句中使用此函数来处理您只想使用合数的情况

>>>
>>> # Work with composite numbers only
>>> number = 8
>>> if not is_prime(number):
...     print(f"{number} is composite")
...
8 is composite

由于您也可能只需要处理合数,因此您可以像在第二个示例中那样is_prime()将其与not运算符组合在一起以进行重用。

编程中的另一种常见情况是找出一个数字是否在特定的数字区间内。要确定一个数字x是否在 Python 中的给定区间内,您可以使用and运算符或适当地链接比较运算符:

>>>
>>> x = 30

>>> # Use the "and" operator
>>> if x >= 20 and x < 40:
...     print(f"{x} is inside")
...
30 is inside

>>> # Chain comparison operators
>>> if 20 <= x < 40:
...     print(f"{x} is inside")
...
30 is inside

在第一个示例中,您使用and运算符创建一个复合布尔表达式,用于检查是否x介于20和之间40。第二个示例进行了相同的检查,但使用了链式运算符,这是 Python 中的最佳实践。

注意:在大多数编程语言中,表达式20 <= x < 40没有意义。它将从评估 开始20 <= x,这是真的。下一步是将真实结果与 进行比较40,这没有多大意义,因此表达式失败。在 Python 中,发生了一些不同的事情。

Python 在内部将这种类型的表达式重写为等效的and表达式,例如x >= 20 and x < 40. 然后执行实际评估。这就是为什么您在上面的示例中得到正确结果的原因。

您可能还需要检查数字是否在目标区间之外。为此,您可以使用or运算符:

>>>
>>> x = 50

>>> if x < 20 or x >= 40:
...     print(f"{x} is outside")
...
50 is outside

or表达式允许您检查是否x20to40区间之外。但是,如果您已经有一个成功检查数字是否在给定区间内的工作表达式,那么您可以重用该表达式来检查相反的条件:

>>>
>>> x = 50

>>> # Reuse the chained logic
>>> if not (20 <= x < 40):
...     print(f"{x} is outside")
50 is outside

在此示例中,您重用最初编码的表达式来确定数字是否在目标区间内。随着not表达式之前,您是否x超出了2040区间。

while 循环

您可以在其中使用not运算符的第二个布尔上下文在您的while循环中。这些循环在满足给定条件时进行迭代,或者直到您通过 using break、 usingreturn或引发异常跳出循环为止。notwhile循环中使用允许您在不满足给定条件时进行迭代。

假设您想编写一个小型 Python 游戏来猜测 1 到 10 之间的随机数。作为第一步,您决定使用input()来捕获用户的姓名。由于名称是游戏其余部分运行的必要条件,因此您需要确保获得它。为此,您可以使用一个while循环来询问用户的姓名,直到用户提供有效姓名为止。

启动您的代码编辑器或 IDEguess.py为您的游戏创建一个新文件。然后添加以下代码:

 1# guess.py
 2
 3from random import randint
 4
 5secret = randint(1, 10)
 6
 7print("Welcome!")
 8
 9name = ""
10while not name:
11    name = input("Enter your name: ").strip()

在 中guess.py,您首先randint()random. 此函数允许您生成给定范围内的随机整数。在这种情况下,您要从1to生成数字10,两者都包括在内。然后向用户打印欢迎消息。

while10 行的循环不断迭代,直到用户提供有效名称。如果用户仅按 未提供名称Enter,则input()返回空字符串 ( "") 并且循环再次运行,因为not ""返回True

现在您可以通过编写代码来提供猜测功能来继续您的游戏。您可以自己完成,也可以展开下面的框以查看可能的实现方式。

实现猜测功能显示隐藏

您对这款小游戏的体验如何?要了解有关 Python 游戏编程的更多信息,请查看PyGame:Python 游戏编程入门

现在您知道如何not在布尔上下文中使用,是时候学习not在非布尔上下文中使用了。这就是您将在下一节中执行的操作。

not在非布尔上下文中使用运算符

由于not运算符还可以将常规对象作为操作数,因此您也可以在非布尔上下文中使用它。换句话说,您可以在if语句或while循环之外使用它。可以说,not运算符在非布尔上下文中最常见的用例是反转给定变量的真值。

假设您需要在循环中交替执行两个不同的操作。在这种情况下,您可以使用标志变量在每次迭代中切换操作:

>>>
>>> toggle = False

>>> for _ in range(4):
...     print(f"toggle is {toggle}")
...     if toggle:
...         # Do something...
...         toggle = False
...     else:
...         # Do something else...
...         toggle = True
...
toggle is False
toggle is True
toggle is False
toggle is True

每次此循环运行时,您都会检查 的真值toggle以决定采取哪种行动。在每个代码块的末尾,您更改 的值,toggle以便您可以在下一次迭代中运行替代操作。更改 的值toggle需要您将类似的逻辑重复两次,这可能容易出错。

您可以使用not运算符来克服这个缺点,并使您的代码更干净、更安全:

>>>
>>> toggle = False

>>> for _ in range(4):
...     print(f"toggle is {toggle}")
...     if toggle:
...         pass  # Do something...
...     else:
...         pass  # Do something else...
...     toggle = not toggle
...
toggle is False
toggle is True
toggle is False
toggle is True

现在突出显示的行交替使用运算符和toggle之间的值。与您之前编写的示例相比,此代码更简洁、更少重复且更不容易出错。TrueFalsenot

使用基于函数的not运算符

and运算符和or运算符不同,运算符在 中not具有等效的基于函数的实现operator。该函数被调用not_()。它接受一个对象作为参数并返回与等效not obj表达式相同的结果:

>>>
>>> from operator import not_

>>> # Use not_() with numeric values
>>> not_(0)
True
>>> not_(42)
False
>>> not_(0.0)
True
>>> not_(42.0)
False
>>> not_(complex(0, 0))
True
>>> not_(complex(42, 1))
False

>>> # Use not_() with strings
>>> not_("")
True
>>> not_("Hello")
False

>>> # Use not_() with other data types
>>> not_([])
True
>>> not_([1, 2, 3])
False
>>> not_({})
True
>>> not_({"one": 1, "two": 2})
False

要使用not_(),您首先需要从operator. 然后,您可以将该函数与任何 Python 对象或表达式一起用作参数。结果与使用等效not表达式相同。

注意: Python 也有and_()or_()函数。然而,它们反映了它们相应的按位运算符而不是布尔运算符

and_()or_()功能也与布尔变量工作:

>>>
>>> from operator import and_, or_

>>> and_(False, False)
False
>>> and_(False, True)
False
>>> and_(True, False)
False
>>> and_(True, True)
True

>>> or_(False, False)
False
>>> or_(False, True)
True
>>> or_(True, False)
True
>>> or_(True, True)
True

在这些示例中,您使用and_()andor_()TrueandFalse作为参数。请注意,表达式的结果分别与andnot运算符的真值表匹配。

当您使用高阶函数(例如 、 等)时,使用not_()函数代替not运算符会很方便。这是一个示例,该示例使用该函数以及通过在列表末尾放置空员工姓名来对员工列表进行排序:map()filter()not_()sorted()

>>>
>>> from operator import not_

>>> employees = ["John", "", "", "Jane", "Bob", "", "Linda", ""]

>>> sorted(employees, key=not_)
['John', 'Jane', 'Bob', 'Linda', '', '', '', '']

在此示例中,您有一个名为的初始列表employees,其中包含一堆名称。其中一些名称是空字符串。调用sorted()using not_()as a keyfunction 来创建一个对员工进行排序的新列表,将空名称移动到列表的末尾。

使用 Python 的not运算符:最佳实践

当您使用not操作符时,您应该考虑遵循一些最佳实践,这些实践可以使您的代码更具可读性、干净和 Pythonic。在本节中,您将了解与not成员资格身份测试的上下文中使用运算符相关的一些最佳实践。

您还将了解否定逻辑如何影响代码的可读性。最后,您将了解一些可以帮助您避免不必要的否定逻辑的便捷技术,这是编程最佳实践。

测试会员资格

当您确定特定对象是否存在于给定的容器数据类型(例如列表、元组、集合或字典)​​中时,成员资格测试通常很有用。要在 Python 中执行此类测试,您可以使用in运算符:

>>>
>>> numbers = [1, 2, 3, 4]

>>> 3 in numbers
True

>>> 5 in numbers
False

in操作者返回True,如果左侧对象是在所述表达式的右侧的容器。否则,它返回False

有时您可能需要检查对象是否不在给定容器中。你怎么能这样做?这个问题的答案是not运营商。

有两种不同的语法可以检查对象是否不在 Python 中的给定容器中。Python 社区认为第一种语法是不好的做法,因为它难以阅读。第二种语法读起来像简单的英语:

>>>
>>> # Bad practice
>>> not "c" in ["a", "b", "c"]
False

>>> # Best practice
>>> "c" not in ["a", "b", "c"]
False

第一个例子有效。但是,前导not使阅读您的代码的人难以确定运算符是否正在处理"c"或处理整个表达式,"c" in ["a", "b", "c"]. 这个细节使表达难以阅读和理解。

第二个例子要清楚得多。Python 文档将第二个示例中的语法称为not in运算符。对于刚开始使用 Python 的人来说,第一种语法可能是一种常见的做法。

现在是时候重新审视检查数字是在数字区间内还是在数字区间外的示例了。如果您仅使用整数,则not in运算符提供了一种更易读的方式来执行此检查:

>>>
>>> x = 30

>>> # Between 20 and 40
>>> x in range(20, 41)
True

>>> # Outside 20 and 40
>>> x not in range(20, 41)
False

第一个示例检查是否x20to40范围或间隔内。请注意,您将其41用作range()要包含40在检查中的第二个参数。

当您使用整数时,这个关于您在何处使用not运算符的小技巧可以对代码可读性产生很大的影响。

检查对象的身份

使用 Python 编码时的另一个常见要求是检查对象的身份。您可以使用 确定对象的身份id()。这个内置函数将一个对象作为参数,并返回一个唯一标识手头对象的整数。这个数字代表对象的身份。

检查身份的实用方法是使用is运算符,这在某些条件语句中非常有用。例如,is运算符最常见的用例之一是测试给定对象是否为 None

>>>
>>> obj = None
>>> obj is None
True

is运营商的回报True,当左操作数具有相同的身份右边的操作数。否则,它返回False

在这种情况下,问题是:如何检查两个对象是否具有不同的身份?同样,您可以使用两种不同的语法:

>>>
>>> obj = None

>>> # Bad practice
>>> not obj is None
False

>>> # Best practice
>>> obj is not None
False

在这两个示例中,您检查是否objNone对象具有相同的标识。第一种语法有点难以阅读且非 Pythonic。该is not语法的方式更加明确和清晰。Python 文档将此语法称为is not运算符,并将其用作最佳实践。

避免不必要的否定逻辑

not运算符使您能够反转给定条件或对象的含义或逻辑。在编程中,这种特征被称为负逻辑否定

正确使用否定逻辑可能会很棘手,因为这种逻辑很难思考和理解,更不用说难以解释了。一般来说,负逻辑比正逻辑意味着更高的认知负荷。所以,只要有可能,你应该使用积极的公式。

下面是一个custom_abs()使用负条件返回输入数字的绝对值的函数示例:

>>>
>>> def custom_abs(number):
...     if not number < 0:
...         return number
...     return -number
...

>>> custom_abs(42)
42

>>> custom_abs(-42)
42

该函数将一个数字作为参数并返回其绝对值。您可以通过使用正逻辑以最小的更改获得相同的结果:

>>>
>>> def custom_abs(number):
...     if number < 0:
...         return -number
...     return number
...

>>> custom_abs(42)
42

>>> custom_abs(-42)
42

就是这样!您custom_abs()现在使用正逻辑。它更简单易懂。为了获得此结果,您删除not并移动了负号 ( -) 以number在其低于 时修改输入0

注意: Python 提供了一个内置函数,称为abs()返回数字输入的绝对值。目的custom_abs()是为了便于主题介绍。

您可以找到许多类似的示例,其中更改比较运算符可以删除不必要的否定逻辑。假设您要检查变量x是否等于给定值。您可以使用两种不同的方法:

>>>
>>> x = 27

>>> # Use negative logic
>>> if not x == 42:
...     print("not 42")
...
not 42

>>> # Use positive logic
>>> if x != 42:
...     print("not 42")
...
not 42

在此示例中,您not通过将比较运算符从等于 ( ==) 更改为不同 ( !=)来删除运算符。在许多情况下,您可以通过使用适当的关系或相等运算符以不同方式表达条件来避免否定逻辑。

但是,有时否定逻辑可以节省您的时间并使您的代码更加简洁。假设您需要一个条件语句来初始化文件系统中不存在的给定文件。在这种情况下,您可以使用not检查文件是否不存在:

from pathlib import Path

file = Path("/some/path/config.ini")

if not file.exists():
    # Initialize the file here...

not运营商允许你反转调用的结果.exists()file。如果.exists()返回False,则需要初始化文件。但是,如果条件为假,则if代码块不会运行。这就是为什么您需要not运算符来反转.exists().

注:上述用途,例如pathlib标准库来处理文件路径。要深入了解这个很酷的库,请查看Python 3 的 pathlib 模块:驯服文件系统

现在想一想如何将这个否定条件变成肯定条件。到目前为止,如果文件存在,您没有任何操作可以执行,因此您可以考虑使用pass语句和附加else子句来处理文件初始化:

if file.exists():
    pass # YAGNI
else:
    # Initialize the file here...

尽管此代码有效,但它违反了“您不需要它”(YAGNI)原则。这是消除负面逻辑的特别坚定的尝试。

这个例子背后的想法是表明有时使用否定逻辑是正确的方法。因此,您应该考虑您的具体问题并选择合适的解决方案。一个好的经验法则是尽可能避免否定逻辑,而不是不惜一切代价避免它。

最后,你应该特别注意避免双重否定。假设您有一个名为的常量NON_NUMERIC,其中包含 Python 无法转换为数字的字符,例如字母和标点符号。从语义上讲,这个常量本身就意味着否定。

现在假设您需要检查给定字符是否为数值。既然你已经有了NON_NUMERIC,你可以考虑使用not来检查条件:

if char not in NON_NUMERIC:
    number = float(char)
    # Do further computations...

这段代码看起来很奇怪,在您作为程序员的职业生涯中,您可能永远不会做这样的事情。然而,做一些类似的事情有时很诱人,比如上面的例子。

此示例使用双重否定。它依赖于NON_NUMERIC,也依赖于not,这使得它难以消化和理解。如果你遇到过这样的一段代码,那么花点时间尝试积极地编写它,或者至少尝试删除一层否定。

结论

Pythonnot是一个逻辑运算符,用于反转布尔表达式和对象的真值。当您需要检查条件语句和while循环中未满足的条件时,它很方便。

您可以使用not运算符来帮助您决定程序中的操作过程。您还可以使用它来反转代码中布尔变量的值。

在本教程中,您学习了如何:

  • 使用 Python 的not运算符
  • not布尔非布尔上下文中使用运算符
  • 用于operator.not_()以函数式执行逻辑否定
  • 尽可能避免代码中不必要的负面逻辑

为此,您编写了一些实际示例来帮助您理解not运算符的一些主要用例,因此您现在可以更好地准备在自己的代码中使用它。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:cloudbbs@huaweicloud.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。