美文网首页生活不易 我用python程序员
操作符详解之成员测试(Python)

操作符详解之成员测试(Python)

作者: import_hello | 来源:发表于2018-07-29 10:02 被阅读1次

    转载请注明出处:https://www.jianshu.com/u/5e6f798c903a

    参考文档:Membership test operations

    成员测试使用 innot in 作为操作符。如果 x 是 s 中的一员,x in s 便会返回 True ;否则返回 Falsex not in sx in s 的真值相反。所有内置序列(sequences)和集合(set)类型都支持成员测试;字典也支持该操作,不过字典将键(key)作为测试对象。对于容器类型(如 list、tuple、set、frozenset、dict 或 collections.deque),表达式 x in y 相当于 any(x is e or x == e for e in y)

    另外,对于 string 和 bytes 类型,仅当 x 是 y 的子串(substring)时,x in y 会返回 True。在这种情况下,成员测试等效于 y.find(x) != -1。由于空字符串被视作任何字符的子串,所以 "" in "abd" 将会返回 True

    对某个对象进行成员测试时,依据对象所持方法的不同,可分为如下三种情况:

    • 第一种情况是在用户(user-defined)定义类中已定义了 __contains__() 方法。那么在进行成员测试时,便会调用该方法。x in yy.__contains__(x) 的真值相同,也就是说如果后者返回 True,前者也会返回 True

      class Fib(object):
          def __reset(self):
              self.a = 1
              self.b = 1
      
          def __init__(self):
              self.__reset()
      
          def __contains__(self, item):
              print("调用 __contains__")
              self.__reset()
              while True:
                  self.a, self.b = self.b, self.a + self.b
                  if item == self.a:
                      return True
                  elif item < self.a:
                      return False
      
          def __reset(self):
              self.a = 1
              self.b = 1
      
      
      a_fib = Fib()
      print(3 in a_fib)
      

      输出:

      调用 __contains__
      True
      
    • 第二种情况是在用户定义类中并没有定义 __contains__(),但定义了 __iter__()。那么在执行 x in y 时,便会通过 __iter__() 对 y 进行迭代,如果在迭代过程中产生了与 x 相等的值,就会返回 True。在迭代过程中,只要确定存在与 x 相等的值,便会停止迭代,不会执行完全部的迭代过程。如果在迭代过程中引发了异常,则如同在成员测试中引发的异常一样。

      class Fib(object):
          def __reset(self):
              self.a = 1
              self.b = 1
      
          def __init__(self):
              self.__reset()
      
          def __iter__(self):
              """测试该方法前,请删除__contains__"""
              print("调用 __iter__()")
              self.__reset()
              return self
      
          def __next__(self):
              self.a, self.b = self.b, self.a + self.b  # 计算下一个值
              if self.a > 100000:  # 退出循环的条件
                  print("停止迭代")
                  raise StopIteration()
              return self.a  # 返回下一个值
          
      a_fib = Fib()
      print(3 in a_fib)
      

      输出:

      调用 __iter__()
      True
      
    • 第三种情况是 __contains__()__iter__() 都没有定义,但定义了 __getitem__()。那么在执行 x in y 时,便会通过 __getitem__() 对 y 中各项逐一索引,仅当存在 x == y[i]( i 为非负整数)时,会返回 True。如果在迭代过程中引发了异常,则如同在成员测试中引发的异常一样。
      tips:定义了 __getitem__() ,但没有定义 __iter__()时,会尝试使用旧式迭代协议,也就是通过 __getitem__() 逐一索引各个元素的方式,进行迭代。另外,我没有看懂文档中的这句话:"all lower integer indices do not raise IndexError exception. "

      class Fib(object):
          def __reset(self):
              self.a = 1
              self.b = 1
      
          def __init__(self):
              self.__reset()
      
          def __getitem__(self, item):
              """测试该方法前,请删除__contains__和__iter__"""
              self.__reset()
              print("调用 __getitem__")
              for x in range(item):
                  self.a, self.b = self.b, self.a + self.b
                  if self.a > 100000:  # 退出循环的条件
                      print("停止迭代")
                      raise StopIteration()
              return self.a
          
      a_fib = Fib()
      print(3 in a_fib)
      

      输出:

      调用 __getitem__
      True
      

    小结:综合以上三种情况,可见成员测试会优先使用 __contains__,如果没有定义该方法才会使用 __iter__(),如果前面两个方法都未定义才会尝试 __getitem__

    相关文章

      网友评论

        本文标题:操作符详解之成员测试(Python)

        本文链接:https://www.haomeiwen.com/subject/wsfamftx.html