广告
返回顶部
首页 > 资讯 > 后端开发 > Python >详解Python字符串对象的实现
  • 284
分享到

详解Python字符串对象的实现

字符串详解对象 2022-06-04 19:06:53 284人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

PyStringObject 结构体 python 中的字符串对象在内部对应一个名叫 PyStrinGobject 的结构体。“ob_shash” 对应字符串经计算过的 hash值, “ob_sval” 指

PyStringObject 结构体

python 中的字符串对象在内部对应一个名叫 PyStrinGobject 的结构体。“ob_shash” 对应字符串经计算过的 hash值, “ob_sval” 指向一段长度为 “ob_size” 的字符串,且该字符串以‘null'结尾(为了兼容C)。“ob_sval”的初始大小为1个字节,且 ob_sval[0]=0(对应空字符串)。若你还想知道“ob_size”被定义的位置,可以看一看 object.h 头文件中 PyObject_VAR_HEAD 对应部分。“ob_sstate” 用来指示某个字符串是否已经存在于intern机制对应的字典中,后面我们会再次提到这一点。


typedef struct {
  PyObject_VAR_HEAD
  long ob_shash;
  int ob_sstate;
  char ob_sval[1];
} PyStringObject;

字符串对象的创建

如下所示,当将一个新的字符串赋给一个变量时,发生了什么?

1>>> s1 = 'abc'
运行以上代码时,内部的 C 函数 “PyString_FromString” 将被调用并生成类似下面的伪代码:


arguments: string object: 'abc'
returns: Python string object with ob_sval = 'abc'
PyString_FromString(string):
  size = length of string
  allocate string object + size for 'abc'. ob_sval will be of size: size + 1
  copy string to ob_sval
  return object

每次用到新的字符串时,都将分配一个字符串对象。

共享字符串对象

Python 有一个优雅的特性,就是变量之间的短字符串是共享的,这一特性可以节省所需的内存空间。短字符串就是那些长度为 0 个或者 1 个字节的字符串。而全局变量 “interned” 对应一个用于索引这些短字符串的字典。数组 “characters” 也可用于索引那些长度为 1 个字节的字符串,比如单个字母。后面我们将看到数组 “characters” 是如何被使用的。


static PyStringObject *characters[UCHAR_MAX + 1];
static PyObject *interned;

下面一起看看:当你在 Python 脚本中将一个短字符串赋值给一个变量时,背后发生了哪些事情。


static PyStringObject *characters[UCHAR_MAX + 1];
static PyObject *interned;

内容为 ‘a' 的字符串对象将被添加到 “interned” 字典中。字典中键(key)是一个指向该字符串对象的指针,而对应的值 就是一个相同的指针。在数组 “characters” 中,这一新的字符串对象在偏移量为 97 的位置被引用,因为字符 ‘a' 的ASCII码值便是 97。变量 “s2” 也指向了这一字符串对象。

查看图片

而,当另外一个变量也被相同的字符串 ‘a' 赋值时,又会如何呢?

1>>> s3 = 'a'
上述代码执行后,将返回之前已创建的内容相同的字符串对象。因此,‘s1' 和 ‘s3' 两个变量都将指向同一个字符串对象。 数组 “characters” 便是用于检测字符串 ‘a' 是否已经存在,若存在,则返回指向该字符串对象的指针。


if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL)
{
  ...
  return (PyObject *)op;
}

查看图片

下面我们新建一个内容为 ‘c' 的短字符串:

1>>> s4 = 'c'
那么,我们将得到如下结果:

查看图片

我们还能发现,当按照下面 Python 脚本中的方式对一个字符串元素进行访问时,数组 “characters” 仍有用武之地。


>>> s5 = 'abc'
>>> s5[0]
'a'

上面第二行代码中,返回的是数组 “characters” 偏移量为 97 的位置内的指针元素,而非新建一个值为 ‘a'的字符串。当我们访问某个字符串中的元素时,一个名叫 “string_item” d的函数将被调用,下方给出了函数体代码。其中,参数 ‘a' 便对应着字符串 “abc”,而参数 ‘i' 便是访问数组的索引值(本例中便为 0 ),函数返回的是指向某个字符串对象的指针。


static PyObject *
string_item(PyStringObject *a, reGISter Py_ssize_t i)
{
  char pchar;
  PyObject *v;
  ...
  pchar = a->ob_sval[i];
  v = (PyObject *)characters[pchar & UCHAR_MAX];
  if (v == NULL)
    // allocate string
  else {
    ...
    Py_INCREF(v);
  }
  return v;
}

数组 “characters” 也可用于函数名长度为 1 时的情形,如下所示:

>>> def a(): pass
字符串查找

下面看看,当你在如下 Python 代码中进行字符串查找操作时,又会有那些事情发生呢?


>>> s = 'adcabcdbdabcabd'
>>> s.find('abcab')
>>> 11

函数 “find” 返回一个索引值,说明是在字符串 “abcd” 的哪个位置找到字符串 “s” 的。若字符串未找到,函数返回值为 -1。

那么,内部到底干了些啥事情?内部调用了一个名为 “fastsearch” 的函数。这个函数是一个介于 BoyerMoore 和 Horspool 算法之间的混合版本,它兼具两者的优良特性。

我们将 “s”(s = ‘adcabcdbdabcabd')称作主字符串,而将 “p”(p = ‘abcab')称作模式串。n 和 m 分别表示字符串 s 和 字符串 p 的长度,其中,n = 15, m = 5。

在如下代码段中,明显看到,程序将进行首次判定:若 m > n,我们就知道必然不能找到这样的索引号,因此函数直接返回 -1 即可。


w = n - m;
if (w < 0)
  return -1;

当 m = 1 时,程序便在字符串 s 中一个个字符地进行遍历,若匹配成功则返回对应的索引位置。在本例中,变量 mode 值为 FAST_SEARCH,意味着我们想获取的是在主字符串中首次匹配的位置,而非模式串在主字符串中成功匹配的次数。


if (m <= 1) {
  ...
  if (mode == FAST_COUNT) {
    ...
  } else {
    for (i = 0; i < n; i++)
      if (s[i] == p[0])
        return i;
  }
  return -1;
}

考虑其他情况,比如 m > 1。首先创建一个压缩的boyer-moore delta 1 table(对应BM算法中的坏字符规则),在此过程中需要声明两个变量:“mask” 和 “skip”。

“mask” 是一个 32 位的位掩码(bitmask),将其最低的 5 个特征位作为开关位。该掩码是通过和模式串 “p” 进行操作产生的。它设计成一个布隆过滤器(bloom filter),用于检测一个字符是否出现在当前字符串中。这种机制使查找操作十分迅速,但是存在伪正的情况(false positives)。关于布隆过滤器,你想有更多了解的话可以看看 这里 。对于本例,下方说明了位掩码具体是如何产生的。


mlast = m - 1

for (mask = i = 0; i < mlast; i++) {
  mask |= (1 << (p[i] & 0x1F));
}

mask |= (1 << (p[mlast] & 0x1F));

字符串 “p” 的第一个字符为 ‘a'。字符‘a'的二进制表示为 97 = 1100001。保留最低的 5 个特征位,我们得到了 00001,因此变 “mask” 初次被设定为 10(1 << 1)。当整个字符串 “p” 都经过处理后,mask 值为 1110。那么,我们应该如何使用这个位掩码呢?通过下方这行代码,我们用其来检测字符 “c” 位于字符串 “p” 哪个位置。

if ((mask & (1 << (c & 0x1F))))
那么,字符 ‘a' 在字符串 “p”(‘abcab')中是否存在呢?1110 & (1 << (‘a' & 0X1F)) 运算结果的值是否为 true 呢?由于 1110 & (1 << (‘a' & 0X1F)) = 1110 & 10 = 10,可知 ‘a' 确实存在于 ‘abcab'。当检测字符 ‘d'时,我们得到的是 false,对于其他字符(从 ‘e' 到 ‘z')也是同样结果。因此,在本例中此类过滤器表现十分出众。 变量 “skip” 对应目标字符在主字符串中最后一个成功匹配的字符的索引位置(从后向前匹配)。假若模式串的最后一个匹配字符在主字符串中不存在,则 “skip” 值为 模式串 “p” 的长度减去 1。本例中,模式串最后一个为匹配字符位 ‘b',由于其在主串查找的当前位置向后跳两个字符后能够匹配到,因此变量 “skip” 的值为2。这个变量应用于一种名叫坏字符跳跃(bad-character skip)的规则。在如下示例中,p = ‘abcab',s = ‘adcabcaba'。从主串 “s” 的 4 号索引位置(从 0 开始计算)开始匹配,若字符匹配成功则向前继续匹配。第一个匹配失败的索引位置为 1(此处 ‘b' 不等于 ‘d')。我们可以看到,在模式串和主串最开始匹配的末端位置往后数三个字符,主串中也有一个 ‘b',而字符 ‘c' 也存在于 “p” 中,因此我们跳过了随后的 ‘b'。

查看图片

下面,看下查找操作的循环部分(真实代码为 C 实现,而非 Python):


for i = 0 to n - m = 13:
  if s[i+m-1] == p[m-1]:
    if s[i:i+mlast] == p[0:mlast]:
      return i
    if s[i+m] not in p:
      i += m
    else:
      i += skip
  else:
    if s[i+m] not in p:
      i += m
return -1

“s[i+m] not in p” 这行测试代码是基于位掩码实现的,“i += skip” 便对应坏字符跳跃。当主串下一个待匹配的字符在 “p” 中并未找到时,则执行 “i += m” 这行代码。

下面来看看,对于字符串 “p” 和 “s” 的匹配,算法具体是如何运行的。前三个步骤与上面类似,接着,字符 ‘d' 在字符串 “p” 并未找到,因此我们直接跳过等于“p”字符串长度的字符数,之后便迅速找到了一个匹配。

查看图片

以上就是带领大家深入了解Python字符串对象实现的整个学习过程,希望对大家学习Python程序设计有所帮助。

--结束END--

本文标题: 详解Python字符串对象的实现

本文链接: https://www.lsjlt.com/news/15582.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 详解Python字符串对象的实现
    PyStringObject 结构体 Python 中的字符串对象在内部对应一个名叫 PyStringObject 的结构体。“ob_shash” 对应字符串经计算过的 hash值, “ob_sval” 指...
    99+
    2022-06-04
    字符串 详解 对象
  • c字符串,string对象,字符串字面值的区别详解
    一、字符串字面值字符串字面值是一串常量字符,字符串字面值常量用双引号括起来的零个或多个字符表示,为兼容C语言,C++中所有的字符串字面值都由编译器自动在末尾添加一个空字符。字符串没有...
    99+
    2022-11-15
    string 字符串
  • python数字和字符串对象
    一、python中的数字对象数字是python当中使用比较广泛的数据类型。1、数字对象类型    ××× int         如:1,2,3    浮点型 Float  如:1.0,2.0    长××× long          在...
    99+
    2023-01-31
    字符串 对象 数字
  • 一文详解JavaScript数组对象和字符串对象
    目录一、数组对象1.数组类型检测2.添加或删除数组元素3.【案例】筛选数组4.数组排序5.数组索引6.【案例】数组去除重复元素7. 数组转换为字符串8.其他方法二、字符串对象1.字符...
    99+
    2023-05-17
    JavaScript字符串对象 JavaScript数组对象
  • JavaScript的内置对象Math和字符串详解
    目录Math对象常用属性常用方法Math.random()字符串方法length属性charAt()charCodeAt()fromCharCode()concat()in...
    99+
    2022-11-12
  • Python中怎么实现一个字符串对象
    这期内容当中小编将会给大家带来有关Python中怎么实现一个字符串对象,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。PyStringObject 结构体Python 中的字符串对象在内部对应一个名叫 Py...
    99+
    2023-06-17
  • python 字符串详解
    目录一、字符串:二、使用:(1)空字符串和 len( ) 函数(2)转译字符( \ )(3)字符串拼接(4)字符串复制(5)不换行打印(6)从控制台读取参数:(7...
    99+
    2022-11-12
  • vuejs如何实现字符串转对象
    本篇内容主要讲解“vuejs如何实现字符串转对象”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“vuejs如何实现字符串转对象”吧!vuejs实现字符串转对象的方法:1、从数据库表中读取原数据;2...
    99+
    2023-06-25
  • Python对象转JSON字符串的方法
    本文实例讲述了Python对象转JSON字符串的方法。分享给大家供大家参考,具体如下: import json class JSONObject(object): def __init__(self...
    99+
    2022-06-04
    字符串 对象 方法
  • Python字符串处理实例详解
    Python字符串处理实例详解 一、拆分含有多种分隔符的字符串 1.如何拆分含有多种分隔符的字符串 问题: 我们要把某个字符串依据分隔符号拆分不同的字段,该字符串包含多种不同的分隔符,例如: s = "...
    99+
    2022-06-04
    字符串 详解 实例
  • Python实现对字符串中字符提取校验
    众所周知,python之所以很方便在一定程度上是因为随时都可能有人又创作了一个好用又方便的python非标准库。 正好有一个小需求需要校验一个python字符串中是否存在某种类型的字...
    99+
    2022-11-11
  • Python中字符串对象语法分享
    目录一、字符串的外观1.字符串字面量2.字符串与多行注释3.字符串编码方式二、字符串对象1.str2.str实现原理3.str中的内置方法4.字符串切片前言:前面提到了Python中...
    99+
    2022-11-13
  • Redis字符串对象实用笔记
    字符串对象 字符串数据类型是Redis里最常用的类型了,它的键和值都是字符串,使用起来非常的方便。虽然字符串数据类型的值都统称为字符串了,但是在实际存储时会根据值的不同自动选择合适的编码。字符串对象的编码...
    99+
    2022-10-18
  • Python 变量教程字节对象与字符串
    目录前言编码解码前言 在 Python 2 中,str 和 bytes 都是相同的 typeByte 对象,而在 Python 3 中,Byte 对象在 Python 3 中定义为&...
    99+
    2022-11-11
  • php的对象转json字符串数组对象
    在PHP开发中,对象转换成JSON字符串或者JSON数组对象是一项非常常见的任务。JSON字符串和JSON数组对象都是一种标准的数据交换格式,它们可以在不同的平台和编程语言之间进行数据交换,并且非常易于阅读和解析。本文将介绍PHP中如何将一...
    99+
    2023-05-19
  • Python 字符串str详解(超详细)
    文章目录 Python内置函数/方法详解—字符串str1、创建字符串1.1 使用 ' ' 或 " " 创建字符串1.2 使用 str()函数 转换为字符串 2、访问字符串2.1 下标索引...
    99+
    2023-10-22
    python 开发语言 pycharm 后端 算法
  • python 遍历字符串(含汉字)实例详解
    python 遍历字符串(含汉字)实例详解 s = "中国china" for j in s: print j 首先一个,你这个'a'是什么编码?可能不是你所想的gbk >>>...
    99+
    2022-06-04
    汉字 遍历 字符串
  • Python实现打印彩色字符串的方法详解
    目录一行代码突出重点内容彩色打印的公式彩色效果汇总封装,让彩色打印更好用函数封装logging 中的使用第三方库print 也许是我们在使用 Python 的时候用的最多的一种操作,...
    99+
    2022-11-11
  • 详解Python中的字符串常识
    目录回顾一下:字符串与长字符串转义字符,比如如何在字符串中输出引号/换行?总结回顾一下:字符串与长字符串 Python非常简单,并没有专门分出一个char(Character)类型(...
    99+
    2022-11-12
  • 详解Python的字符串格式化
    目录Python在字符串格式化的两种方式%,关于整数的输出%,关于浮点数的输出%,关于字符串的输出format格式化输出format,位置匹配(最常用)总结format,指定数据类型...
    99+
    2023-05-16
    Python字符串 字符串格式化
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作