“in”运算符有副作用吗?

Sim*_*ter 3 python

我有将字节写入串行端口(pySerial 3.5)然后接收字节的代码。

该代码也应该适用于 micropython,它使用 UART 而不是 pySerial。对于 UART,我必须在读取之前添加一个小的延迟。

用户不必传递是否添加该延迟的附加标志,因为该serial_port对象已经是特定于平台的,例如 UART 实现提供了.any()pySerial 实现所没有的方法。

所以我的第一次尝试是检查这个方法,并且只有在它存在时才延迟。

def __init__(self, serial_port):
    self.serial_port.write(my_bytes)

    # When checking for any on serial_port, I receive no bytes.
    if "any" in self.serial_port:
        print("UART specific delay will happen here")
    # When instead checking with getattr(self.serial_port, "any", None), bytes come in

    raw_config = self.serial_port.read(128)

Run Code Online (Sandbox Code Playgroud)

一旦我添加此"any" in self.serial_port检查,该read()方法就会返回一个空字节数组。

当我删除支票时,我再次获得字节。当我用 替换检查时getattr(self.serial_port, "any", None),我也得到了字节。当我只是跑步time.sleep()或做其他事情时,我会得到字节。当我添加in检查时,字节消失了。

为什么在地球上?支票不是in应该没有副作用吗?

(所有运行均仅使用 pySerial 端口执行。)

kay*_*ya3 6

PySerial 文档中没有提到这一点,但这是该类继承自io.IOBase标准库的结果。状态的文档IOBase

IOBase(及其子类)支持迭代器协议,这意味着IOBase可以迭代对象以生成流中的行。

因此,尽管 PySerial 类实际上并未实现该__contains__方法,并且实际上其层次结构中的任何其他类(包括 IOBase)也没有实现该方法,但迭代器协议为运算符的工作提供了不同的机制:in

对于未定义__contains__()但定义了的用户定义类__iter__()x in y如果在迭代 时生成表达式为 true 的True某个值。zx is z or x == zy

因此,in操作符迭代流以测试成员资格,并且该操作具有从流中消耗数据的副作用(因为这就是迭代 IO 套接字在 Python 中的工作原理)。