为什么空格会影响相等字符串的同一性比较? [复制]

2023-12-08

我注意到,向相同的字符串添加空格会使它们使用时比较不相等is,而非空间版本比较相等。

a = 'abc'
b = 'abc'
a is b
#outputs: True

a = 'abc abc'
b = 'abc abc'
a is b
#outputs: False

我读过了这个关于比较字符串的问题== and is。我认为这是一个不同的问题,因为空格字符正在改变行为,而不是字符串的长度。看:

a = 'abc'
b = 'abc'
a is b # True

a = 'gfhfghssrtjyhgjdagtaerjkdhhgffdhfdah'
b = 'gfhfghssrtjyhgjdagtaerjkdhhgffdhfdah'
a is b # True

为什么向字符串添加空格会改变比较的结果?


python解释器根据一定的标准缓存一些字符串,第一个abc字符串被缓存并用于两者,但第二个不是。对于小整数来说也是一样的-5 to 256.

因为字符串是内部/缓存分配的a and b to "abc" makes a and b指向内存中的相同对象,因此使用is,检查两个对象是否实际上是同一个对象,返回True.

第二串abc abc未缓存,因此它们是内存中两个完全不同的对象,因此使用以下方法进行身份检查is回报False。这次a is not b。它们都指向内存中的不同对象。

In [43]: a = "abc" # python caches abc
In [44]: b = "abc" # it reuses the object when assigning to b
In [45]: id(a)
Out[45]: 139806825858808    # same id's, same object in memory
In [46]: id(b)
Out[46]: 139806825858808    
In [47]: a = 'abc abc'   # not cached  
In [48]: id(a)
Out[48]: 139806688800984    
In [49]: b = 'abc abc'    
In [50]: id(b)         # different id's different objects
Out[50]: 139806688801208

缓存字符串的标准是字符串是否只有letters, 下划线 and numbers在字符串中,因此在您的情况下,空格不符合标准。

使用解释器时,在一种情况下,即使字符串不满足上述条件(多次赋值),您也可能最终指向同一个对象。

In [51]: a,b  = 'abc abc','abc abc'

In [52]: id(a)
Out[52]: 139806688801768

In [53]: id(b)
Out[53]: 139806688801768

In [54]: a is b
Out[54]: True

看着codeobject.c 源来决定我们看到的标准NAME_CHARS决定什么可以被拘留:

#define NAME_CHARS \
    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"

/* all_name_chars(s): true iff all chars in s are valid NAME_CHARS */

static int
all_name_chars(unsigned char *s)
{
    static char ok_name_char[256];
    static unsigned char *name_chars = (unsigned char *)NAME_CHARS;

    if (ok_name_char[*name_chars] == 0) {
        unsigned char *p;
        for (p = name_chars; *p; p++)
            ok_name_char[*p] = 1;
    }
    while (*s) {
        if (ok_name_char[*s++] == 0)
            return 0;
    }
    return 1;
}

长度为 0 或 1 的字符串将始终被共享,正如我们在PyString_FromStringAndSize函数在字符串对象.c source.

/* share short strings */
    if (size == 0) {
        PyObject *t = (PyObject *)op;
        PyString_InternInPlace(&t);
        op = (PyStringObject *)t;
        nullstring = op;
        Py_INCREF(op);
    } else if (size == 1 && str != NULL) {
        PyObject *t = (PyObject *)op;
        PyString_InternInPlace(&t);
        op = (PyStringObject *)t;
        characters[*str & UCHAR_MAX] = op;
        Py_INCREF(op);
    }
    return (PyObject *) op;
}

与问题没有直接关系,但对于那些感兴趣的人PyCode_New也来自codeobject.c源代码显示了在构建代码对象时,一旦字符串满足以下条件,如何保留更多字符串all_name_chars.

PyCodeObject *
PyCode_New(int argcount, int nlocals, int stacksize, int flags,
       PyObject *code, PyObject *consts, PyObject *names,
       PyObject *varnames, PyObject *freevars, PyObject *cellvars,
       PyObject *filename, PyObject *name, int firstlineno,
       PyObject *lnotab)
{
    PyCodeObject *co;
    Py_ssize_t i;
    /* Check argument types */
    if (argcount < 0 || nlocals < 0 ||
        code == NULL ||
        consts == NULL || !PyTuple_Check(consts) ||
        names == NULL || !PyTuple_Check(names) ||
        varnames == NULL || !PyTuple_Check(varnames) ||
        freevars == NULL || !PyTuple_Check(freevars) ||
        cellvars == NULL || !PyTuple_Check(cellvars) ||
        name == NULL || !PyString_Check(name) ||
        filename == NULL || !PyString_Check(filename) ||
        lnotab == NULL || !PyString_Check(lnotab) ||
        !PyObject_CheckReadBuffer(code)) {
        PyErr_BadInternalCall();
        return NULL;
    }
    intern_strings(names);
    intern_strings(varnames);
    intern_strings(freevars);
    intern_strings(cellvars);
    /* Intern selected string constants */
    for (i = PyTuple_Size(consts); --i >= 0; ) {
        PyObject *v = PyTuple_GetItem(consts, i);
        if (!PyString_Check(v))
            continue;
        if (!all_name_chars((unsigned char *)PyString_AS_STRING(v)))
            continue;
        PyString_InternInPlace(&PyTuple_GET_ITEM(consts, i));
    }

这个答案基于使用 cpython 解释器的简单分配,就与简单分配之外的函数或任何其他功能相关的实习而言,没有询问也没有回答。

如果任何对 C 代码有更深入了解的人有任何需要添加的内容,请随时编辑。

有一个更彻底的解释here整个字符串实习。

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

为什么空格会影响相等字符串的同一性比较? [复制] 的相关文章

随机推荐

  • 如何使用 Twisted 获取 IRC 频道的用户列表

    我正在尝试使用获取频道的用户列表 self say channel WHO 100 我怎样才能得到回复 我应该重写哪个方法 这里有一些额外的方法可以帮助您取得进一步的进展 您处理给定的回复RPL NAME通过定义一个方法irc RPL NA
  • 如何使用Maven只签署三个jar并将它们推送到Maven Central?

    更新 参见跟进问题 我有一个 Java 库 其构建过程完全用 Ant 编写 项目的沙箱 源目录 我在其中编辑代码 是 R jeffy programming sandbox xbnjava 它的构建 输出 目录是 R jeffy progr
  • 如何使用 PHP 将撇号从文本区域传递到 MySQL

    我有一个文本区域 用户也可以添加注释 在下一页上我使用 POST Comments 显示输入的内容 我有一个编辑按钮可以返回并查看输入的内容并编辑注释 但是当我显示 POST Comments 它显示了撇号之前的所有内容 Example 最
  • 使用 $.ajax 时成功后访问 $(this):function()

    使用 jquery 时 如何在 success function 后访问 this 的值 无论我尝试什么 似乎我都做不到 add click function etc etc ajax type GET url data data data
  • C# 库做 fft 和 ifft? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 是否有免费的 C 库可以进行快速傅立叶变换及其逆变换 Math NET 和 Aforce 都基于 Exocortex DSP 库 http www
  • Hiredis 等待消息

    我正在使用hiredis C 库连接到redis 服务器 我无法弄清楚如何在订阅新消息后等待新消息 我的代码如下所示 signal SIGPIPE SIG IGN struct event base base event base new
  • Qt:MouseMove 无法运行

    在我的 Qt 应用程序中 我需要跟踪鼠标移动 为此 我创建了一个eventfilter我正确安装了它 如下所示 bool iArmMainWindow eventFilter QObject obj QEvent event if even
  • 为什么 Node.js 将传入数据分成块?

    Node js 中的以下代码不会将所有传入数据记录在括号内 而是将数据分成块 例如 如果传入数据是 ABCDEF XYZ 它将数据记录为 ABC DEF XYZ 而不是 ABCDEF XYZ 当然数据要大得多 字母表只是一个例子 我应该如何
  • 为什么Java I/O中的一个字节可以代表一个字符?

    为什么Java I O中的一个字节可以代表一个字符 我看到这些字符只是 ASCII 那么它就不是动态的了 对吧 对此有什么解释吗 字节流和字符流有什么区别 字节不是字符 独自一人 他们甚至无法代表人物 从计算角度来说 字符 是数字代码 或代
  • 将可执行文件链接到的所有 dll 复制到可执行目录

    这个问题询问类似的问题 但只需要手动指定要复制的dll 我的问题是 有没有一种方法可以简单地让 CMake 复制链接到可执行库的所有 dll 而不需要手动告诉 CMake 要复制哪些文件 有时 CMake 更了解是否需要 dll 例如 在安
  • 使用 C# Parallel.ForEach 循环处理 SFTP 文件不处理下载

    我正在使用 Renci SSH NET 软件包版本 2016 我正在从外部服务器下载文件 我通常每 6 秒就能下载一个文件 当你有数千个文件时 这很糟糕 我最近尝试改变foreach循环到Parallel ForEach 这样做将文件下载时
  • Powershell 中的 Lambda 表达式

    我有一段 C 代码 它使用 lambda 表达式将委托传递给方法 我怎样才能在 PowerShell 中实现这一目标 例如 以下是 C 代码 string input string pattern
  • 如何将 perfmon 插件与 jmeter-maven-plugin 一起使用?

    我目前正在开发一个基于 jmeter 的项目 使用 jmeter maven 插件运行测试 到目前为止 一切正常 直到我添加了 perfmon 插件 添加它们以使用 jmeter UI 获取每秒事务数和随时间变化的响应时间 按照说明进行操作
  • 如何解决 IE 不支持 :after 的问题?

    我有一堆清单 ul li class first Item 1 li li Item 2 li li class last Item 3 li ul 风格与 li after content li last after content 这一
  • 如何在 C++ 中编译位于不同文件中的模板?

    当我将所有源代码放入一个文件中时 程序就成功构建了 但是 当我将它们拆分为头文件时 出现链接错误 我的程序的主要内容 C Class Templates cpp include
  • 仅在 Android 中首次启动时显示设置屏幕

    我正在制作一个 Android 应用程序 但我不知道如何使设置屏幕仅在第一次出现 这就是应用程序的工作方式 用户在安装后启动应用程序并显示欢迎 设置屏幕 一旦用户完成设置 设置屏幕将永远不会再次出现 除非用户重新安装应用程序 我怎样才能做到
  • iOS 照片权限要求第二次

    我目前正在使用 aasset 这是第一次请求许可 如果想第二次或每次用户阻止它时弹出权限 这怎么可能 没有办法第二次显示权限提示 处理权限提示的最好方法是在触发权限提示之前向用户解释 阅读 AssetsLibrary框架中的call方法 如
  • 如何将多个(excel)文件读入R? [复制]

    这个问题在这里已经有答案了 我有数百个中等大小的 Excel 文件 5000 到 50 0000 行 大约 100 列 要加载到 R 中 它们具有明确定义的命名模式 例如x 1 xlsx x 2 xlsx etc 如何以最快 最直接的方式将
  • ADT 插件更新后使用某种库的所有 Android 项目都会抛出 ClassNotFoundException [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 我正在使用 Eclipse 我在之后就面临这个问题谷歌
  • 为什么空格会影响相等字符串的同一性比较? [复制]

    这个问题在这里已经有答案了 我注意到 向相同的字符串添加空格会使它们使用时比较不相等is 而非空间版本比较相等 a abc b abc a is b outputs True a abc abc b abc abc a is b outpu