最近遇到判断字典中是否存在空字符串‘’,这个很好判断,直接用:‘’ in ['a','b','c'],就可以直接判断出来;但是当我对字符串使用 “in” 方法进行判断的时候,发现:‘’ in ‘abc' 仍然会返回True,对于这个问题,之前一直没有注意到过其中的原理,现在去进行探索总结一下:

首先,查看官方文档:https://docs.python.org/2/reference/expressions.html#not-in

文档在5.9.2中:Membership test operations中是如下说明的:

大概翻译一下意思就是说:  

  “in” 和 “not in” 是对集合成员的检测操作,如果 x 在 集合s 中的话那么 x in s 返回True,否则返回False。x not in s 跟 x in s 判断是相反的。 成员的检测被绑定到序列;如果集合是序列,并且包含与该对象相等的元素,则对象是集合的成员。然而,对于许多其他对象类型来说,即使不是序列,但是支持成员测试也是有意义的。特别是,dict(key) 和 sets 支持成员资格测试。

  • “列表” 和 “元祖” 类型:当且仅当,'y' 中 存在一个下标 ’i‘ 使得 x is y[i] 或者 x == y[i] 成立,x in y 才会返回 True
  • “Unicode” 和 “String” 类型: 要使 'x in y' return True 成立,当且仅当,’x‘ 是 ’y‘ 的一个子字符串。有个等效的测试为 y.find(x) != -1。注:’x‘ 和 ’y‘ 不需要相同的类型;比如:u'ab' in 'abc' 也会返回True。空字符串是任何字符串的子字符串,所以,“” in 'abc' 会返回True。

  在版本2.3的时候被改变了:之前的版本,’x‘ 被要求是长度为 1 的字符串。

  • 对于用户自定义的类,分为以下三种情况考虑:
  1. 对于有__contains__()方法的用户自定义类:如果 y.__contains__(x) 为 True,则 x in y 返回True
  2. 对于没有定义__contains__()方法,但是定义了__iter__()方法:如果 有值 'z' 在对 ’y‘ 进行迭代的时候 x==z 成立,那么 x in y 会返回True,如果在迭代过程中引发异常,则会抛出该 in 异常。
  3. 对于定义了__getitem__()方法的类:当且仅当含有一个非负的整数下标 i 使得 x == y[i] 成立,那么 x in y 才会返回True,所有较低的整数索引不会引发IndexError异常。(如果有任何其他的异常出现,也会出现 in 操作出现异

   “not in” 操作和 “in” 操作产生的结果相反

看完官方文档后,对于判断“String”类型的时候,可以通过 y.find(x) != -1 来测试其是否成立,但是这个原理是怎么来的,还是想进一步进行探究,下面查看Python2.7的源码:

首先,猜测在源码中首先应该和对象类型有关系,然后找到发现有typeobject.c文件,浏览后发现,含有如下代码:

SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc,
"x.__contains__(y) <==> y in x"),

然后接下来推测去找跟__contains__方法有关的和 上面说到的 find() 方法有关的源码:

  • 在stringlib头文件文件夹中,发现有 find.h 文件,然后在其中发现了如下函数:
Py_LOCAL_INLINE(int)
stringlib_contains_obj(PyObject* str, PyObject* sub)
{
return stringlib_find(
STRINGLIB_STR(str), STRINGLIB_LEN(str),
STRINGLIB_STR(sub), STRINGLIB_LEN(sub),
) != -;
}
  • 然后进一步去找到 stringlib_find() 的定义:
Py_LOCAL_INLINE(Py_ssize_t)
stringlib_find(const STRINGLIB_CHAR* str, Py_ssize_t str_len,
const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,
Py_ssize_t offset)
{
Py_ssize_t pos; if (str_len < )
return -;
if (sub_len == )
return offset; pos = fastsearch(str, str_len, sub, sub_len, -, FAST_SEARCH); if (pos >= )
pos += offset; return pos;
}
  • 从这里可以看到 当str_len == 0的时候,返回 offset,而 offset 已经初始化为了 0,从这里也可以大概得出:y.find(x) != -1,当 ’x‘ 为 ’空字符串‘ 时返回 0;当 ’x‘ 存在 'y' 中的时候,返回 对应的偏移量。然后接下来就会判断返回True 还是False。

因为源码关联性的原因,接下来可以在 stringobject.c 文件中,结合 find.h 进行对于其返回值的原理查看,这里就不一一列出来了。

源码目录:

  Objects/Stringlib/find.h

  Objects/typeobject.c

  Objects/stringobject.c

由 '' in 'abc' return True 引发的思考----Python 成员测试操作的更多相关文章

  1. Spring之LoadTimeWeaver——一个需求引发的思考---转

    原文地址:http://www.myexception.cn/software-architecture-design/602651.html Spring之LoadTimeWeaver——一个需求引 ...

  2. 解决一道leetcode算法题的曲折过程及引发的思考

    写在前面 本题实际解题过程是 从 40秒 --> 24秒 -->1.5秒 --> 715ms --> 320ms --> 48ms --> 36ms --> ...

  3. 密码验证连续多位相同或者顺序字符引发的思考.md

    目录 密码验证连续多位相同或者顺序字符引发的思考 需求 思考 实现 总结 参考 密码验证连续多位相同或者顺序字符引发的思考 需求 虽然用户对于这种复杂的密码验证恨之入骨,但是有时出于安全的考虑,我们系 ...

  4. 从一个聊天信息引发的思考之Android事件分发机制

         转载请声明:http://www.cnblogs.com/courtier/p/4295235.html 起源:        我在某一天看到了下面的一条信息(如下图),我想了下(当然不是这 ...

  5. class_copyIvarList方法获取实例变量问题引发的思考

    在runtime.h中,你可以通过其中的一个方法来获取实例变量,那就是class_copyIvarList方法,具体的实现如下: - (NSArray *)ivarArray:(Class)cls { ...

  6. js中return,return true,return false三者的用法及区别

    return其实就是return undefined; 1.语法及返回方式 ①返回控制与函数结果 语法为:return 表达式; 语句结果函数的执行,返回调用函数,而且把表达式的值作为函数结果返回出去 ...

  7. 一个ScheduledExecutorService启动的Java线程无故挂掉引发的思考

    2018年12月12日18:44:53 一个ScheduledExecutorService启动的Java线程无故挂掉引发的思考 案件现场 不久前,在开发改造公司一个端到端监控日志系统的时候,出现了一 ...

  8. SQLAlchemy并发写入引发的思考

    背景 近期公司项目中加了一个积分机制,用户登录签到会获取登录积分,但会出现一种现象就是用户登录时会增加双倍积分,然后生成两个积分记录.此为问题  问题分析 项目采用微服务架构,下图为积分机制流程   ...

  9. FastAdmin Bootstrap-Table 关于客户端模式(由 计算所有页的的总数引发的思考)

    Bootstrap-Table 关于客户端模式(由 计算所有页的的总数引发的思考) 昨天群里有小伙伴询问 Bootstrap-Table 有没有计算所有页的总数. [吐槽]★隔壁老王-杭州 @F4NN ...

随机推荐

  1. SpringCloud--Ribbon负载均衡

    Ribbon实现客户端负载均衡 负载均衡:是对系统的高可用.网络压力的缓解和处理能力扩容的重要手段之一. 硬件负载均衡:主要通过在服务器节点之间安装专门用于负载均衡的设备: 软件负载均衡:通过在服务器 ...

  2. RSA算法原理与加密解密 求私钥等价求求模反元素 等价于分解出2个质数 (r*X+1)%[(p-1)(q-1)]=0

    Rsapaper.pdf http://people.csail.mit.edu/rivest/Rsapaper.pdf [概述Abstract 1.将字符串按照双方约定的规则转化为小于n的正整数m, ...

  3. gitlab-runner ---CI

    gitlab-runner: https://segmentfault.com/a/1190000007180257 https://mp.weixin.qq.com/s?__biz=MjM5MTA1 ...

  4. 转!idea 破解版 安装

    原博文地址:https://blog.csdn.net/everest_man/article/details/78985879 1.官网下载  Ultimate版本 2.http://idea.la ...

  5. Python开发【笔记】:如何在字典遍历中删除key值?

    数据遍历时不能犯傻系列 前言: 针对字典做一些操作时,有时会遇到下面的状况,列如我们需要把data中的key值根据replace中的映射关系进行替换(Caller替换为caller) data = { ...

  6. MySql创建函数与过程,触发器, shell脚本与sql的相互调用。

    一:函数 1:创建数据库和表deptartment, mysql> use DBSC; Database changed mysql), ), )); Query OK, rows affect ...

  7. Mac Atom的PHP插件

    首先,需要在 ~/.atom目录下创建 .atom文件,写入如下内容: strict-ssl = false http_proxy = socks5://127.0.0.1:16888 https_p ...

  8. 【原创】PHPstorm本地修改同步保存到远程服务器

    PHPstorm设置本地修改的代码同步保存到远程服务器: 设置里面搜索“Deployment”,选择+号,然后选择SFTP: 填写远程主机的信息: 然后选择Mappings,填写本地代码路径和远程主机 ...

  9. Linux /proc/pid目录下各文件含义

    /proc 是一个伪文件系统, 被用作内核数据结构的接口, 而不仅仅是解释说明/dev/kmem. /proc 里的大多数文件都是只读的, 但也可以通过写一些文件来改变内核变量. ( Linux 内核 ...

  10. macbook 蓝牙关闭按钮灰色的

    PRAM重置:1.关机,拔掉所有外设,只连接电源线2.按开机键,接着马上同时按住 command+option+p+r 键,按住后听到三次dang的开机音后放开3.电脑会自行启动,进到登录页面后点关机 ...