Python 的“in”和“not in”运算符:检查成员资格

2023-12-05

蟒蛇的innot in运算符允许您快速确定给定值是否属于值集合的一部分。这种类型的检查在编程中很常见,通常称为会员资格测试在Python中。因此,这些运算符被称为会员经营者.

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

  • 履行会员资格测试使用innot in运营商
  • 使用innot in与不同的数据类型
  • 与 一起工作operator.contains(), 这等价函数in操作员
  • 提供支持innot in在你的自己的班级

为了充分利用本教程,您需要了解 Python 的基本知识,包括内置数据类型,例如列表, 元组, 范围, 字符串, , 和字典。您还需要了解 Python发电机, 理解力, 和.

源代码: 点击此处下载免费源代码您将使用它在 Python 中执行成员资格测试innot in.

Python 中的成员资格测试入门

有时您需要查明某个值是否存在于值集合中。换句话说,您需要检查给定值是否是成员值的集合。这种检查通常称为会员资格测试.

可以说,执行此类检查的自然方法是迭代这些值并将它们与目标值进行比较。您可以在以下人员的帮助下完成此操作for循环和一个条件语句.

考虑以下is_member()功能:

>>>
>>> def is_member(value, iterable):
...     for item in iterable:
...         if value is item or value == item:
...             return True
...     return False
...

该函数有两个参数,目标value和值的集合,通常称为iterable。循环遍历iterable而条件语句检查目标是否value等于当前值。请注意,条件检查对象身份is或为了价值平等与等于运算符 (==)。这些测试略有不同但互补。

如果条件为真,则函数回报 True,跳出循环。这次提前回归短路循环操作。如果循环结束时没有任何匹配项,则函数返回False:

>>>
>>> is_member(5, [2, 3, 5, 9, 7])
True

>>> is_member(8, [2, 3, 5, 9, 7])
False

第一次致电is_member()回报True因为目标值,5,是当前列表中的成员,[2, 3, 5, 9, 7]。第二次调用该函数返回False因为8不存在于输入值列表中。

像上面这样的成员资格测试在编程中非常常见和有用,以至于 Python 有专门的运算符来执行这些类型的检查。您可以了解会员经营者如下表所示:

Operator Description Syntax
in Returns True if the target value is present in a collection of values. Otherwise, it returns False. value in collection
not in Returns True if the target value is not present in a given collection of values. Otherwise, it returns False. value not in collection

布尔运算符,Python 通过使用常见的英语单词而不是可能令人困惑的符号作为运算符来提高可读性。

笔记:不要混淆in 关键词当它作为会员运营商与in中的关键字for循环语法。它们具有完全不同的含义。这in运算符检查某个值是否在值集合中,而in中的关键字for循环表示您要从中绘制的可迭代对象。

与许多其他运营商一样,innot in是二元运算符。这意味着您可以通过连接两个操作数来创建表达式。在这种情况下,这些是:

  1. 左操作数:您要在值集合中查找的目标值
  2. 右操作数:可以找到目标值的值的集合

成员资格测试的语法如下所示:

value in collection

value not in collection

在这些表达中,value可以是任何Python对象。同时,collection可以是任何可以保存值集合的数据类型,包括列表、元组, 字符串, , 和字典。它也可以是一个实现了.__contains__()显式支持成员资格测试或迭代的方法或用户定义的类。

如果您使用innot in运算符正确,那么您使用它们构建的表达式将始终计算为布尔值价值。换句话说,这些表达式将始终返回True或者False。另一方面,如果您尝试在不支持成员资格测试的事物中找到价值,那么您将得到类型错误. 之后,您将了解有关支持成员资格测试的 Python 数据类型的更多信息。

既然您知道什么是会员运营商,那么是时候了解他们如何运作的基础知识了。

蟒蛇的in操作员

为了更好地理解in运算符,您将首先编写一些小的说明性示例来确定给定值是否是在一个列表:

>>>
>>> 5 in [2, 3, 5, 9, 7]
True

>>> 8 in [2, 3, 5, 9, 7]
False

第一个表达式返回True因为5出现在您的号码列表中。第二个表达式返回False因为8不存在于列表中。

根据in操作员文档,像这样的表达式value in collection相当于下面的代码:

any(value is item or value == item for item in collection)

生成器表达式包含在调用中任何()构建一个布尔值列表,该列表是通过检查目标是否value具有相同的身份或等于当前itemcollection。致电给any()检查结果布尔值中是否有任何一个是True,在这种情况下函数返回True。如果所有的值都是False, 然后any()回报False.

蟒蛇的not in操作员

not in会员运营商的做法恰恰相反。使用此运算符,您可以检查给定值是否不在值的集合:

>>>
>>> 5 not in [2, 3, 5, 9, 7]
False

>>> 8 not in [2, 3, 5, 9, 7]
True

在第一个例子中,你得到False因为5是在[2, 3, 5, 9, 7]。在第二个例子中,你得到True因为8不在值列表中。这种否定逻辑可能看起来像是绕口令。为了避免混淆,请记住您正在尝试确定该值是否为not给定值集合的一部分。

笔记:not value in collection构造的工作原理与value not in collection一。然而,前一种结构更难以阅读。因此,您应该使用not in作为单个操作符而不是使用not否定结果in.

通过对会员运营商如何工作的快速概述,您已准备好进入下一个级别并了解如何innot in使用不同的内置数据类型。

使用innot in使用不同的 Python 类型

全部内置序列——比如列表、元组、范围对象和字符串——支持成员资格测试innot in运营商。集合和字典等集合也支持这些测试。默认情况下,字典上的成员资格操作会检查字典是否具有给定的键。但是,字典还具有显式方法,允许您将成员运算符与键、值和键值对一起使用。

在以下部分中,您将了解使用的一些特殊性innot in具有不同的内置数据类型。您将从列表、元组和range开始事情的对象。

列表、元组和范围

到目前为止,您已经编写了一些使用innot in运算符来确定给定值是否存在于现有值列表中。对于这些示例,您已明确使用list对象。因此,您已经熟悉成员资格测试如何与列表一起使用。

对于元组,成员运算符的工作方式与对于列表的工作方式相同:

>>>
>>> 5 in (2, 3, 5, 9, 7)
True

>>> 5 not in (2, 3, 5, 9, 7)
False

这里没有什么惊喜。这两个示例的工作方式与以列表为中心的示例相同。在第一个示例中,in运算符返回True因为目标值,5,在元组中。在第二个例子中,not in返回相反的结果。

对于列表和元组,成员资格运算符使用搜索算法迭代底层集合中的项目。因此,当你的迭代变得更长时,搜索时间成正比增加。使用大O表示法,你会说对这些数据类型的成员资格操作有一个时间复杂度在).

如果您使用innot in运营商与range对象,那么你会得到类似的结果:

>>>
>>> 5 in range(10)
True

>>> 5 not in range(10)
False

>>> 5 in range(0, 10, 2)
False

>>> 5 not in range(0, 10, 2)
True

到那个时刻range对象,乍一看似乎没有必要使用成员资格测试。大多数时候,您会事先知道结果范围内的值。但如果你使用的是range()带有在运行时确定的参数?

笔记:创建时range对象,您最多可以传递三个参数给range()。这些论点是start, stop, 和step。他们定义了这个数字开始范围,范围必须达到的数字停止创造价值,以及生成的值之间。

考虑以下示例,其中使用随机的运行时确定参数的数字:

>>>
>>> from random import randint

>>> 50 in range(0, 100, randint(1, 10))
False

>>> 50 in range(0, 100, randint(1, 10))
False

>>> 50 in range(0, 100, randint(1, 10))
True

>>> 50 in range(0, 100, randint(1, 10))
True

在您的计算机上,您可能会得到不同的结果,因为您正在使用随机范围。在这些具体的例子中,step是唯一变化的值。在实际代码中,您可以有不同的值startstop以及。

为了range对象,成员资格测试背后的算法使用表达式计算给定值的存在(value - start) % step) == 0,这取决于用于创建手头范围的参数。这使得会员测试非常高效当他们操作时range对象。在这种情况下,你会说它们的时间复杂度是复杂度(1).

笔记:列表、元组和range对象有一个.index()方法,返回给定值在基础序列中第一次出现的索引。此方法对于在序列中定位值非常有用。

有些人可能认为他们可以使用该方法来确定某个值是否在序列中。但是,如果该值不在序列中,则.index()提出一个值错误:

>>>
>>> (2, 3, 5, 9, 7).index(8)
Traceback (most recent call last):
    ...
ValueError: tuple.index(x): x not in tuple

您可能不想通过引发异常来确定某个值是否在序列中,因此您应该使用成员运算符而不是.index()以此目的。

请记住,成员资格测试中的目标值可以是任何类型。该测试将检查该值是否在目标集合中。例如,假设您有一个假设的应用程序,用户使用用户名和密码进行身份验证。你可以有这样的东西:

# users.py

username = input("Username: ")
password = input("Password: ")

users = [("john", "secret"), ("jane", "secret"), ("linda", "secret")]

if (username, password) in users:
    print(f"Hi {username}, you're logged in!")
else:
    print("Wrong username or password")

这是一个幼稚的例子。不太可能有人会这样处理他们的用户和密码。但示例表明目标值可以是任何数据类型。在本例中,您使用表示给定用户的用户名和密码的字符串元组。

以下是该代码在实践中的工作原理:

$ python users.py
Username: john
Password: secret
Hi john, you're logged in!

$ python users.py
Username: tina
Password: secret
Wrong username or password

在第一个示例中,用户名和密码是正确的,因为它们位于users列表。在第二个示例中,用户名不属于任何注册用户,因此身份验证失败。

在这些示例中,需要注意的是,数据在登录元组中的存储顺序至关重要,因为类似("john", "secret")不等于("secret", "john")在元组比较中,即使它们具有相同的项目。

在本节中,您探索了一些示例,这些示例展示了具有常见 Python 内置序列的成员资格运算符的核心行为。然而,还剩下一个内置序列。是的,弦!在下一节中,您将了解成员运算符如何在 Python 中处理此数据类型。

弦乐

Python 字符串是每个 Python 开发人员工具包中的基本工具。与元组、列表和范围一样,字符串也是序列,因为它们的项或字符按顺序存储在内存中。

您可以使用innot in当您需要确定目标字符串中是否存在给定字符时,请使用字符串运算符。例如,假设您使用字符串来设置和管理给定资源的用户权限:

>>>
>>> class User:
...     def __init__(self, username, permissions):
...         self.username = username
...         self.permissions = permissions
...

>>> admin = User("admin", "wrx")
>>> john = User("john", "rx")

>>> def has_permission(user, permission):
...     return permission in user.permissions
...

>>> has_permission(admin, "w")
True
>>> has_permission(john, "w")
False

User类有两个参数,一个用户名和一组权限。要提供权限,您可以使用一个字符串,其中w意味着用户拥有允许,r意味着用户拥有许可,以及x暗示执行权限。请注意,这些字母与您在 Unix 风格中找到的字母相同文件系统权限.

里面的会员测试has_permission()检查当前是否user有一个给定的permission或不返回True或者False因此。为此,需要将in运算符搜索权限字符串以查找单个字符。在此示例中,您想知道用户是否有允许。

但是,您的权限系统有一个隐藏的问题。如果使用空字符串调用该函数会发生什么?这是你的答案:

>>>
>>> has_permission(john, "")
True

因为空字符串始终被视为任何其他字符串的子字符串,所以像这样的表达式"" in user.permissions将返回True。根据谁有权访问您的用户权限,这种成员资格测试行为可能意味着您的系统存在安全漏洞。

您还可以使用隶属度运算符来确定是否字符串包含子字符串:

>>>
>>> greeting = "Hi, welcome to Real Python!"

>>> "Hi" in greeting
True
>>> "Hi" not in greeting
False

>>> "Hello" in greeting
False
>>> "Hello" not in greeting
True

对于字符串数据类型,表达式如下substring in stringTrue如果substring是其一部分string。否则,表达式为False.

笔记:与列表、元组等其他序列不同range对象、字符串提供了.find()在现有字符串中搜索给定子字符串时可以使用的方法。

例如,您可以执行以下操作:

>>>
>>> greeting.find("Python")
20

>>> greeting.find("Hello")
-1

如果子字符串存在于底层字符串中,则.find()返回子字符串在字符串中开始的索引。如果目标字符串不包含子字符串,那么你会得到-1因此。所以,像这样的表达式string.find(substring) >= 0将相当于substring in string测试。

然而,成员资格测试更具可读性和明确性,这使得它在这种情况下更可取。

对字符串使用成员资格测试时要记住的重要一点是字符串比较区分大小写:

>>>
>>> "PYTHON" in greeting
False

本次会员测试返回False因为字符串比较区分大小写,并且"PYTHON"大写的不存在于greeting。要解决这种区分大小写的问题,您可以使用以下任一方法标准化所有字符串。上()或者。降低()方法:

>>>
>>> "PYTHON".lower() in greeting.lower()
True

在此示例中,您使用.lower()将目标子字符串和原始字符串转换为小写字母。此转换欺骗了隐式字符串比较中的大小写敏感性。

发电机

发电机功能生成器表达式创建高效内存迭代器作为。。而被知道生成器迭代器。为了提高内存效率,这些迭代器按需生成项目,而不在内存中保留完整的值系列。

实际上,生成器函数是功能使用的是屈服其正文中的声明。例如,假设您需要一个生成器函数,它接受数字列表并返回一个迭代器,该迭代器从原始数据生成平方值。在这种情况下,您可以执行以下操作:

>>>
>>> def squares_of(values):
...     for value in values:
...         yield value ** 2
...

>>> squares = squares_of([1, 2, 3, 4])

>>> next(squares)
1
>>> next(squares)
4
>>> next(squares)
9
>>> next(squares)
16
>>> next(squares)
Traceback (most recent call last):
    ...
StopIteration

该函数返回一个生成器迭代器,根据需要生成平方数。您可以使用内置的下一个()函数从迭代器中检索连续值。当生成器迭代器完全消耗完时,它会引发一个StopIteration例外以传达没有剩下更多值的情况。

您可以在生成器函数上使用成员运算符,例如squares_of():

>>>
>>> 4 in squares_of([1, 2, 3, 4])
True
>>> 9 in squares_of([1, 2, 3, 4])
True
>>> 5 in squares_of([1, 2, 3, 4])
False

in当您将它与生成器迭代器一起使用时,运算符按预期工作,返回True如果该值存在于迭代器中并且False否则。

然而,在检查生成器的成员资格时,您需要注意一些事情。生成器迭代器只会生成每个项目一次。如果您消耗了所有项目,那么迭代器将耗尽,您将无法再次迭代它。如果您仅使用生成器迭代器中的一些项目,那么您只能迭代剩余的项目。

当你使用in或者not in在生成器迭代器上,运算符将在搜索目标值时消耗它。如果该值存在,则运算符将消耗直到目标值的所有值。其余值在生成器迭代器中仍然可用:

>>>
>>> squares = squares_of([1, 2, 3, 4])

>>> 4 in squares
True

>>> next(squares)
9
>>> next(squares)
16
>>> next(squares)
Traceback (most recent call last):
    ...
StopIteration

在这个例子中,4位于生成器迭代器中,因为它是2。所以,in回报True。当你使用next()从中检索值square, 你得到9,这是3。此结果确认您无法再访问前两个值。您可以继续拨打电话next()直到你得到一个StopIteration当生成器迭代器耗尽时出现异常。

同样,如果生成器迭代器中不存在该值,则运算符将完全消耗迭代器,并且您将无法访问其任何值:

>>>
>>> squares = squares_of([1, 2, 3, 4])

>>> 5 in squares
False

>>> next(squares)
Traceback (most recent call last):
    ...
StopIteration

在此示例中,in操作员消耗squares彻底、回归False因为目标值不在输入数据中。因为生成器迭代器现在已耗尽,所以调用next()squares作为一个论点提出StopIteration.

您还可以使用生成器表达式创建生成器迭代器。这些表达式使用相同的语法列表推导式但替换方括号 ([]) 带圆括号 (())。您可以使用innot in带有生成器表达式结果的运算符:

>>>
>>> squares = (value ** 2 for value in [1, 2, 3, 4])
>>> squares
<generator object <genexpr> at 0x1056f20a0>

>>> 4 in squares
True

>>> next(squares)
9
>>> next(squares)
16
>>> next(squares)
Traceback (most recent call last):
    ...
StopIteration

squares 多变的现在保存由生成器表达式生成的迭代器。该迭代器从输入数字列表中生成平方值。生成器表达式中的生成器迭代器与生成器函数中的生成器迭代器的工作方式相同。因此,当您在成员资格测试中使用它们时,同样的规则也适用。

当您使用innot in带有生成器迭代器的运算符。当您使用无限迭代器时,可能会出现此问题。下面的函数返回一个产生无限整数的迭代器:

>>>
>>> def infinite_integers():
...     number = 0
...     while True:
...         yield number
...         number += 1
...

>>> integers = infinite_integers()
>>> integers
<generator object infinite_integers at 0x1057e8c80>

>>> next(integers)
0
>>> next(integers)
1
>>> next(integers)
2
>>> next(integers)
3
>>> next(integers)

infinite_integers()函数返回一个生成器迭代器,它存储在integers。该迭代器根据需要生成值,但请记住,将会有无限的值。因此,在此迭代器中使用成员运算符并不是一个好主意。为什么?好吧,如果目标值不在生成器迭代器中,那么您将陷入无限循环,这将使您的执行悬挂.

字典和集合

Python 的成员运算符也可用于字典和集合。如果您使用in或者not in直接在字典上使用运算符,然后它会检查字典是否有给定的键。您还可以使用以下命令进行此检查.keys()方法,这更明确地表达了您的意图。

您还可以检查给定值或键值对是否在字典中。要执行这些检查,您可以使用.values()。项目()方法分别为:

>>>
>>> likes = {"color": "blue", "fruit": "apple", "pet": "dog"}

>>> "fruit" in likes
True
>>> "hobby" in likes
False
>>> "blue" in likes
False

>>> "fruit" in likes.keys()
True
>>> "hobby" in likes.keys()
False
>>> "blue" in likes.keys()
False

>>> "dog" in likes.values()
True
>>> "drawing" in likes.values()
False

>>> ("color", "blue") in likes.items()
True
>>> ("hobby", "drawing") in likes.items()
False

在这些示例中,您使用in操作员直接在您的likes字典来检查是否"fruit", "hobby", 和"blue"键是否在字典中。请注意,即使"blue"是一个值likes,测试返回False因为它只考虑键。

接下来,您将使用.keys()方法得到相同的结果。在这种情况下,显式的方法名称可以让其他程序员阅读您的代码时更加清楚您的意图。

检查一个值是否像"dog"或者"drawing"存在于likes,你使用.values()方法,它返回一个查看对象与底层字典中的值。类似地,检查一个键值对是否包含在likes, 你用.items()。请注意,目标键值对必须是键和值按顺序排列的两项元组。

如果您使用集合,则成员资格运算符的工作方式与列表或元组的工作方式相同:

>>>
>>> fruits = {"apple", "banana", "cherry", "orange"}

>>> "banana" in fruits
True
>>> "banana" not in fruits
False

>>> "grape" in fruits
False
>>> "grape" not in fruits
True

这些示例表明您还可以使用隶属度运算符检查给定值是否包含在集合中innot in.

现在您知道如何innot in运算符使用不同的内置数据类型,是时候通过几个示例将这些运算符付诸实践了。

把Python的innot in运营商行动起来

会员资格测试innot in是编程中非常常见的操作。您会在许多现有的 Python 代码库中找到此类测试,并且也会在您的代码中使用它们。

在以下部分中,您将学习如何根据以下内容替换布尔表达式or具有成员资格测试的操作员。由于成员资格测试在您的代码中非常常见,因此您还将学习如何使这些测试更加高效。

更换链式or运营商

使用隶属度测试将复合布尔表达式替换为多个or运算符是一种有用的技术,可以让您简化代码并使其更具可读性。

要查看此技术的实际应用,假设您需要编写一个函数,将颜色名称作为字符串并确定它是否是原色。为了解决这个问题,您将使用RGB(红、绿、蓝)颜色型号:

>>>
>>> def is_primary_color(color):
...     color = color.lower()
...     return color == "red" or color == "green" or color == "blue"
...

>>> is_primary_color("yellow")
False

>>> is_primary_color("green")
True

In is_primary_color(),您使用复合布尔表达式,该表达式使用or运算符检查输入颜色是否为红色、绿色或蓝色。尽管此函数按预期工作,但条件可能会令人困惑并且难以阅读和理解。

好消息是,您可以用紧凑且可读的成员资格测试替换上述条件:

>>>
>>> def is_primary_color(color):
...     primary_colors = {"red", "green", "blue"}
...     return color.lower() in primary_colors
...

>>> is_primary_color("yellow")
False

>>> is_primary_color("green")
True

现在你的函数使用in运算符检查输入颜色是否为红色、绿色或蓝色。将原色集分配给正确命名的变量,例如primary_colors还有助于使您的代码更具可读性。最后的检查现在已经很清楚了。任何阅读您代码的人都会立即明白您正在尝试根据 RGB 颜色模型确定输入颜色是否为原色。

如果您再次查看该示例,您会发现原色已存储在一个集合中。为什么?您将在下一节中找到答案。

编写高效的成员资格测试

Python 使用一个数据结构称为哈希表实现字典和集合。哈希表有一个显着的特性:在数据结构中查找任何给定值大约需要相同的时间,无论表有多少个值。使用 Big O 表示法,您会说哈希表中的值查找的时间复杂度为复杂度(1),这使得它们速度超级快。

现在,哈希表的这个特性与字典和集合的成员资格测试有什么关系?嗯,事实证明innot in操作员在操作这些类型时工作速度非常快。此细节允许您通过在成员资格测试中优先使用字典和集合而不是列表和其他序列来优化代码的性能。

要了解集合比列表效率高多少,请继续创建以下脚本:

# performance.py

from timeit import timeit

a_list = list(range(100_000))
a_set = set(range(100_000))

list_time = timeit("-1 in a_list", number=1, globals=globals())
set_time = timeit("-1 in a_set", number=1, globals=globals())

print(f"Sets are {(list_time / set_time):.2f} times faster than Lists")

该脚本创建一个包含十万个值的整数列表和一个包含相同数量元素的集合。然后该脚本计算确定该数字是否所需的时间-1位于列表和集合中。你事先就知道-1未出现在列表或集中。因此,成员资格操作员必须在获得最终结果之前检查所有值。

正如您已经知道的,当in运算符在列表中搜索值,它使用时间复杂度为的算法在)。另一方面,当in运算符在集合中搜索值,它使用哈希表查找算法,其时间复杂度为复杂度(1)。这一事实可以在性能方面产生很大的差异。

继续吧运行你的脚本从命令行使用以下命令:

$ python performance.py
Sets are 1563.33 times faster than Lists

尽管您的命令的输出可能略有不同,但当您在此特定成员资格测试中使用集合而不是列表时,它仍然会显示出显着的性能差异。对于列表,处理时间将与值的数量成正比。对于一组,任何数量的值的时间都几乎相同。

此性能测试表明,当您的代码对大型值集合进行成员资格检查时,您应该尽可能使用集合而不是列表。当您的代码在执行期间执行多个成员资格测试时,您还将受益于集合。

但是,请注意,仅仅为了执行一些成员资格测试而将现有列表转换为集合并不是一个好主意。请记住,将列表转换为集合是一个操作在)时间复杂度。

使用operator.contains()用于会员测试

in运算符具有等效功能操作员模块,它出现在标准库。该函数称为包含()。它需要两个参数——值的集合和目标值。它返回True如果输入集合包含目标值:

>>>
>>> from operator import contains

>>> contains([2, 3, 5, 9, 7], 5)
True

>>> contains([2, 3, 5, 9, 7], 8)
False

第一个参数contains()是值的集合,第二个参数是目标值。请注意,参数的顺序与常规成员资格操作不同,其中目标值排在第一位。

当您使用类似工具时,此功能会派上用场地图(), 或者筛选()处理代码中的可迭代对象。例如,假设您有一堆笛卡尔点作为元组存储在列表中。您想要创建一个仅包含不在坐标轴上的点的新列表。使用filter()函数,你可以想出以下解决方案:

>>>
>>> points = [
...     (1, 3),
...     (5, 0),
...     (3, 7),
...     (0, 6),
...     (8, 3),
...     (2, 0),
... ]

>>> list(filter(lambda point: not contains(point, 0), points))
[(1, 3), (3, 7), (8, 3)]

在此示例中,您使用filter()检索不包含的点0协调。为此,您使用contains()在一个拉姆达功能。因为filter()返回一个迭代器,您将所有内容包装在调用中list()将迭代器转换为点列表。

尽管上面示例中的构造有效,但它非常复杂,因为它意味着导入contains(),创建一个lambda函数在其之上,并调用几个函数。您可以使用列表理解获得相同的结果contains()或者not in直接操作员:

>>>
>>> [point for point in points if not contains(point, 0)]
[(1, 3), (3, 7), (8, 3)]

>>> [point for point in points if 0 not in point]
[(1, 3), (3, 7), (8, 3)]

上面的列表推导式比等效的列表推导式更短并且可以说更具可读性filter()从前面的例子中调用。它们也不太复杂,因为您不需要创建lambda函数或调用list(),所以你减少了知识要求。

支持用户定义的类中的成员资格测试

提供一个.__包含__()方法是在您自己的类中支持成员资格测试的最明确和首选的方法。 Python会自动调用这个特殊方法当您在成员资格测试中使用类的实例作为正确的操作数时。

您可能会添加一个.__contains__()方法仅适用于用作值集合的类。这样,类的用户将能够确定给定值是否存储在类的特定实例中。

举个例子,假设您需要创建一个最小的数据结构来存储以下值LIFO(后进先出)原则。自定义数据结构的要求之一是支持成员资格测试。因此,您最终编写了以下课程:

# stack.py

class Stack:
    def __init__(self):
        self.items = []

    def push(self, item):
        self.items.append(item)

    def pop(self):
        return self.items.pop()

    def __contains__(self, item):
        return item in self.items

你的Stack类支持堆栈数据结构的两个核心功能。你可以一个值到栈顶并且pop来自堆栈顶部的值。请注意,您的数据结构使用list对象在引擎盖下存储和操作实际数据。

您的班级还支持会员测试innot in运营商。为此,该类实现了.__contains__()方法依赖于in运营商本身。

要试用您的课程,请继续运行以下代码:

>>>
>>> from stack import Stack

>>> stack = Stack()
>>> stack.push(1)
>>> stack.push(2)
>>> stack.push(3)

>>> 2 in stack
True
>>> 42 in stack
False
>>> 42 not in stack
True

你们班完全支持innot in运营商。做得好!您现在知道如何支持您自己的班级中的会员测试。

请注意,如果给定的类有.__contains__()方法,那么该类不必是可迭代的,成员运算符也可以工作。在上面的例子中,Stack不可迭代,并且运算符仍然可以工作,因为它们从.__contains__()方法。

除了提供一个之外,至少还有两种方法来支持用户定义的类中的成员资格测试.__contains__()方法。如果您的班级有.__iter__()或一个.__getitem__()方法,那么innot in运营商也工作。

考虑以下替代版本Stack:

# stack.py

class Stack:
    def __init__(self):
        self.items = []

    def push(self, item):
        self.items.append(item)

    def pop(self):
        return self.items.pop()

    def __iter__(self):
        yield from self.items

.__iter__()特殊的方法让你的班级可迭代的,这足以让成员资格测试发挥作用。来吧,尝试一下!

支持成员资格测试的另一种方法是实施.__getitem__()在类中使用从零开始的整数索引来处理索引操作的方法:

# stack.py

class Stack:
    def __init__(self):
        self.items = []

    def push(self, item):
        self.items.append(item)

    def pop(self):
        return self.items.pop()

    def __getitem__(self, index):
        return self.items[index]

Python 自动调用.__getitem__()执行时的方法索引操作在底层对象上。在此示例中,当您执行以下操作时stack[0],您将获得第一项Stack实例。 Python 利用.__getitem__()使会员运营商正常运作。

结论

现在您知道如何使用 Python 执行成员资格测试innot in运营商。这种类型的测试允许您检查给定值是否存在于值集合中,这是编程中非常常见的操作。

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

  • 跑步会员资格测试使用Python的innot in运营商
  • 使用innot in运营商有不同的数据类型
  • 与 一起工作operator.contains(), 这等价函数in操作员
  • 支持innot in在你的自己的班级

有了这些知识,您就可以使用 Python 进行成员资格测试了innot in代码中的运算符。

源代码: 点击此处下载免费源代码您将使用它在 Python 中执行成员资格测试innot in.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python 的“in”和“not in”运算符:检查成员资格 的相关文章

  • 如果两点之间的距离低于某个阈值,则从列表中删除点

    我有一个点列表 只有当它们之间的距离大于某个阈值时 我才想保留列表中的点 因此 从第一个点开始 如果第一个点和第二个点之间的距离小于阈值 那么我将删除第二个点 然后计算第一个点和第三个点之间的距离 如果该距离小于阈值 则比较第一点和第四点
  • Lighttpd 和 cgi python

    我正在尝试通过 lighttpd 执行一些 python 脚本 但是当我尝试运行它时 我只得到一个要求我下载的空白文件 lighttpd conf server modules mod access mod alias mod access
  • 如何手动计算分类交叉熵?

    当我手动计算二元交叉熵时 我应用 sigmoid 来获取概率 然后使用交叉熵公式并平均结果 logits tf constant 1 1 0 1 2 labels tf constant 0 0 1 1 1 probs tf nn sigm
  • 中断 Select 以添加另一个要在 Python 中监视的套接字

    我正在 Windows XP 应用程序中使用 TCP 实现点对点 IPC 我正在使用select and socketPython 2 6 6 中的模块 我有三个 TCP 线程 一个读取线程通常会阻塞select 一个通常等待事件的写入线程
  • Django 的内联管理:一个“预填充”字段

    我正在开发我的第一个 Django 项目 我希望用户能够在管理中创建自定义表单 并向其中添加字段当他或她需要它们时 为此 我在我的项目中添加了一个可重用的应用程序 可在 github 上找到 https github com stephen
  • 使用特定的类/函数预加载 Jupyter Notebook

    我想预加载一个笔记本 其中包含我在另一个文件中定义的特定类 函数 更具体地说 我想用 python 来做到这一点 比如加载一个配置文件 包含所有相关的类 函数 目前 我正在使用 python 生成笔记本并在服务器上自动启动它们 因为不同的
  • 在 django ORM 中查询时如何将 char 转换为整数?

    最近开始使用 Django ORM 我想执行这个查询 select student id from students where student id like 97318 order by CAST student id as UNSIG
  • 安装了 32 位的 Python,显示为 64 位

    我需要运行 32 位版本的 Python 我认为这就是我在我的机器上运行的 因为这是我下载的安装程序 当我重新运行安装程序时 它会将当前安装的 Python 版本称为 Python 3 5 32 位 然而当我跑步时platform arch
  • 使用 Python 从文本中删除非英语单词

    我正在 python 上进行数据清理练习 我正在清理的文本包含我想删除的意大利语单词 我一直在网上搜索是否可以使用像 nltk 这样的工具包在 Python 上执行此操作 例如给出一些文本 Io andiamo to the beach w
  • 使用字典映射数据帧索引

    为什么不df index map dict 工作就像df column name map dict 这是尝试使用index map的一个小例子 import pandas as pd df pd DataFrame one A 10 B 2
  • 从Python中的字典列表中查找特定值

    我的字典列表中有以下数据 data I versicolor 0 Sepal Length 7 9 I setosa 0 I virginica 1 I versicolor 0 I setosa 1 I virginica 0 Sepal
  • 如何使用 Mysql Python 连接器检索二进制数据?

    如果我在 MySQL 中创建一个包含二进制数据的简单表 CREATE TABLE foo bar binary 4 INSERT INTO foo bar VALUES UNHEX de12 然后尝试使用 MySQL Connector P
  • Numpy - 根据表示一维的坐标向量的条件替换数组中的值

    我有一个data多维数组 最后一个是距离 另一方面 我有距离向量r 例如 Data np ones 20 30 100 r np linspace 10 50 100 最后 我还有一个临界距离值列表 称为r0 使得 r0 shape Dat
  • javascript 是否有等效的 __repr__ ?

    我最接近Python的东西repr这是 function User name password this name name this password password User prototype toString function r
  • 根据列 value_counts 过滤数据框(pandas)

    我是第一次尝试熊猫 我有一个包含两列的数据框 user id and string 每个 user id 可能有多个字符串 因此会多次出现在数据帧中 我想从中导出另一个数据框 一个只有那些user ids列出至少有 2 个或更多string
  • 如何解决 PDFBox 没有 unicode 映射错误?

    我有一个现有的 PDF 文件 我想使用 python 脚本将其转换为 Excel 文件 目前正在使用PDFBox 但是存在多个类似以下错误 org apache pdfbox pdmodel font PDType0Font toUnico
  • 在本地网络上运行 Bokeh 服务器

    我有一个简单的 Bokeh 应用程序 名为app py如下 contents of app py from bokeh client import push session from bokeh embed import server do
  • Python ImportError:无法导入名称 __init__.py

    我收到此错误 ImportError cannot import name life table from cdc life tables C Users tony OneDrive Documents Retirement retirem
  • 如何应用一个函数 n 次? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 假设我有一个函数 它接受一个参数并返回相同类型的结果 def increment x return x 1 如何制作高阶函数repeat可以
  • 如何计算Python中字典中最常见的前10个值

    我对 python 和一般编程都很陌生 所以请友善 我正在尝试分析包含音乐信息的 csv 文件并返回最常听的前 n 个乐队 从下面的代码中 每听一首歌曲都是一个列表中的字典条目 格式如下 album Exile on Main Street

随机推荐