`in` 为生成器定义
`in` defined for generator
为什么要为生成器定义 in
运算符?
>>> def foo():
... yield 42
...
>>>
>>> f = foo()
>>> 10 in f
False
可能的用例是什么?
我知道 range(...)
对象定义了一个 __contains__
函数,这样我们就可以做这样的事情:
>>> r = range(10)
>>> 4 in r
True
>>> r.__contains__
<method-wrapper '__contains__' of range object at 0x7f82bd51cc00>
但是f
上面没有__contains__
方法。
生成器是可迭代的,因此有一个 .__iter__
方法,可用于检查成员资格
Expressions docs on Membership test operations
中描述了其行为方式
For user-defined classes which do not define __contains__()
but do define __iter__()
, x in y
is True
if some value z
, for which the expression x is z or x == z
is true, is produced while iterating over y. If an exception is raised during the iteration, it is as if in
raised that exception.
强调我的!
这会弹出整个生成器,而您使用 42
的示例根本不包括 10
的测试值
>>> def foo():
... yield 5
... yield 10
...
>>> f = foo()
>>> 10 in f
True
>>> 10 in f
False
“可能的用例是什么?”检查生成器是否会产生一些值。
Dunder 方法作为 hooks 用于与它们关联的特定语法。 __contains__
不是某种到 x in y
的一对一映射。语言最终定义了这些运算符的语义。
从 documentation of membership testing 中,我们看到 x in y
有多种计算方法,具体取决于所涉及对象的各种属性。我已经为生成器对象突出了相关的一个,它没有定义 __contains__
但是是可迭代的,即它们定义了一个 __iter__
方法:
The operators in and not in test for membership. x in s
evaluates to
True
if x is a member of s, and False otherwise. x not in s
returns
the negation of x in s
. All built-in sequences and set types support
this as well as dictionary, for which in tests whether the dictionary
has a given key. For container types such as list, tuple, set,
frozenset, dict, or collections.deque, the expression x in y is
equivalent to any(x is e or x == e for e in y)
.
For the string and bytes types, x in y
is True
if and only if x
is a
substring of y
. An equivalent test is y.find(x) != -1
. Empty strings
are always considered to be a substring of any other string, so "" in "abc"
will return True.
For user-defined classes which define the __contains__()
method, x in
y returns True
if y.__contains__(x)
returns a true value, and False
otherwise.
For user-defined classes which do not define contains() but do
define __iter__()
, x in y
is True
if some value z
, for which the
expression x is z or x == z
is true, is produced while iterating over
y
. If an exception is raised during the iteration, it is as if in
raised that exception.
Lastly, the old-style iteration protocol is tried: if a class defines
__getitem__()
, x in y
is True
if and only if there is a non-negative integer index i
such that x is y[i] or x == y[i]
, and no lower integer
index raises the IndexError exception. (If any other exception is
raised, it is as if in raised that exception).
The operator not in
is defined to have the inverse truth value of in.
总而言之,x in y
将为以下对象定义:
- 是字符串还是字节,定义为子串关系
- 定义
__contains__
的类型
- 作为迭代器的类型,即定义
__iter__
- 旧式迭代协议(依赖于
__getitem__
)
生成器分为 3。
一个更广泛的观点,你真的不应该直接使用 dunder 方法,除非你真的理解他们在做什么。即使那样,最好还是避免它。
通常不值得尝试通过使用具有以下效果的东西来变得可信或简洁:
x.__lt__(y)
而不是:
x < y
你至少应该明白,这可能会发生:
>>> (1).__lt__(3.)
NotImplemented
>>>
如果您只是天真地做类似 filter((1).__lt__, iterable)
的事情,那么您可能遇到了错误。
为什么要为生成器定义 in
运算符?
>>> def foo():
... yield 42
...
>>>
>>> f = foo()
>>> 10 in f
False
可能的用例是什么?
我知道 range(...)
对象定义了一个 __contains__
函数,这样我们就可以做这样的事情:
>>> r = range(10)
>>> 4 in r
True
>>> r.__contains__
<method-wrapper '__contains__' of range object at 0x7f82bd51cc00>
但是f
上面没有__contains__
方法。
生成器是可迭代的,因此有一个 .__iter__
方法,可用于检查成员资格
Expressions docs on Membership test operations
中描述了其行为方式For user-defined classes which do not define
__contains__()
but do define__iter__()
,x in y
isTrue
if some valuez
, for which the expressionx is z or x == z
is true, is produced while iterating over y. If an exception is raised during the iteration, it is as ifin
raised that exception.
强调我的!
这会弹出整个生成器,而您使用 42
的示例根本不包括 10
>>> def foo():
... yield 5
... yield 10
...
>>> f = foo()
>>> 10 in f
True
>>> 10 in f
False
“可能的用例是什么?”检查生成器是否会产生一些值。
Dunder 方法作为 hooks 用于与它们关联的特定语法。 __contains__
不是某种到 x in y
的一对一映射。语言最终定义了这些运算符的语义。
从 documentation of membership testing 中,我们看到 x in y
有多种计算方法,具体取决于所涉及对象的各种属性。我已经为生成器对象突出了相关的一个,它没有定义 __contains__
但是是可迭代的,即它们定义了一个 __iter__
方法:
The operators in and not in test for membership.
x in s
evaluates toTrue
if x is a member of s, and False otherwise.x not in s
returns the negation ofx in s
. All built-in sequences and set types support this as well as dictionary, for which in tests whether the dictionary has a given key. For container types such as list, tuple, set, frozenset, dict, or collections.deque, the expression x in y is equivalent toany(x is e or x == e for e in y)
.For the string and bytes types,
x in y
isTrue
if and only ifx
is a substring ofy
. An equivalent test isy.find(x) != -1
. Empty strings are always considered to be a substring of any other string, so"" in "abc"
will return True.For user-defined classes which define the
__contains__()
method, x in y returnsTrue
ify.__contains__(x)
returns a true value, andFalse
otherwise.For user-defined classes which do not define contains() but do define
__iter__()
,x in y
isTrue
if some valuez
, for which the expressionx is z or x == z
is true, is produced while iterating overy
. If an exception is raised during the iteration, it is as if in raised that exception.Lastly, the old-style iteration protocol is tried: if a class defines
__getitem__()
,x in y
isTrue
if and only if there is a non-negative integer indexi
such thatx is y[i] or x == y[i]
, and no lower integer index raises the IndexError exception. (If any other exception is raised, it is as if in raised that exception).The operator
not in
is defined to have the inverse truth value of in.
总而言之,x in y
将为以下对象定义:
- 是字符串还是字节,定义为子串关系
- 定义
__contains__
的类型
- 作为迭代器的类型,即定义
__iter__
- 旧式迭代协议(依赖于
__getitem__
)
生成器分为 3。
一个更广泛的观点,你真的不应该直接使用 dunder 方法,除非你真的理解他们在做什么。即使那样,最好还是避免它。
通常不值得尝试通过使用具有以下效果的东西来变得可信或简洁:
x.__lt__(y)
而不是:
x < y
你至少应该明白,这可能会发生:
>>> (1).__lt__(3.)
NotImplemented
>>>
如果您只是天真地做类似 filter((1).__lt__, iterable)
的事情,那么您可能遇到了错误。