百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

一文掌握Python 的字符串驻留是如何工作的

off999 2024-09-14 07:08 25 浏览 0 评论

Python 是一种灵活的编程语言,它提供了各种机制来优化性能和内存使用情况。其中一种优化技术就是字符串驻留。

字符串驻留

字符串驻留是一个根植于内存和性能优化的概念,尤其是在 Python 等编程语言中。

什么是字符串驻留?

字符串驻留的核心是只存储每个不同不可变字符串值的一个副本。不可变字符串一旦创建就无法更改。这种不变性是驻留过程的关键,因为它确保存储的字符串值保持不变,从而允许多个引用安全地指向同一内存位置。

当一个字符串被驻留时,任何其他具有相同值的字符串都将引用相同的内存位置。这意味着 Python 不会为相同的字符串创建新的内存分配,而是重用现有的内存分配。这种重用使字符串驻留成为一种有效的优化技术。

为什么字符串驻留很有用?

字符串驻留有几个显著的好处:

  1. 内存效率:通过仅存储相同字符串的一个副本,Python 减少了使用的内存量。这对于处理大量重复字符串值的应用程序(例如文本处理、数据解析和日志系统)尤其有益。
  2. 性能改进:驻留字符串可以加快比较速度。通常,比较两个字符串需要逐个检查每个字符,这对于长字符串来说可能非常耗时。但是,如果字符串被驻留,Python 可以简单地比较它们的内存地址。如果地址相同,则字符串相等。这种指针比较比逐个字符比较快得多。
  3. 一致性和安全性:字符串驻留有助于保持一致性,并避免因拥有同一字符串的多个副本而可能出现的潜在错误。由于驻留字符串是不可变的且存储在单个位置,因此无意中修改一个字符串(如果字符串是可变的)不会影响其他字符串,从而确保数据完整性。

何时应使用字符串驻留?

了解字符串驻留有益的场景可以帮助您做出明智的决定,确定何时在代码中使用它:

  1. 重复字符串的高频率:如果您的应用程序涉及处理大量重复字符串,则驻留可以显著节省内存并提高性能。
  2. 性能关键的字符串比较:在字符串比较是性能瓶颈的情况下,实习可以通过利用指针相等性检查而不是逐个字符的比较来加快比较速度。
  3. 资源受限的环境:在内存受限的环境中,例如嵌入式系统或在有限硬件上运行的应用程序,驻留可以帮助优化内存使用情况。

限制和注意事项

虽然字符串驻留提供了明显的好处,但重要的是要注意它的局限性:

  • 内存开销:驻留需要在内存节省和管理驻留字符串池的开销之间进行权衡。驻留过多的字符串(尤其是较大的字符串)可能会导致驻留字符串池本身的内存使用量增加。
  • 垃圾回收:只要引用了 Interned 字符串,它们通常就不会被垃圾回收。如果 Interned 字符串使用不当,则可能会导致内存泄漏。
  • 并非总是自动:Python 不会自动驻留所有字符串。了解何时手动驻留字符串对于实现所需的性能和内存优势至关重要。

Python 中的字符串驻留是如何工作的

Python 的字符串驻留机制在优化内存使用和提高性能方面起着至关重要的作用。了解 Python 中字符串驻留的工作原理需要探索自动和手动驻留过程,并识别发生驻留的具体场景。

自动驻留

Python 会自动保留某些字符串以优化内存使用和性能。此过程是隐式的,通常涉及类似于标 识符且经常重复使用的字符串。

标识符的驻留

Python 中的标识符(例如变量名和函数名)会自动保留。这些标识符通常由字母数字字符和下划线组成。Python 之所以保留这些字符串,是因为它们在程序执行过程中被广泛使用且经常被比较。

示例:标识符的自动驻留

a = 'name'
 b = 'name' 
print (a is b)   # 输出:True

 x = 'variable_1'
 y = 'variable_1' 
print (x is y)   # 输出:True

在此示例中,字符串'name''variable_1'由 Python 自动驻留。因此,ab引用相同的内存位置,与x和一样y

短字符串

Python 还会驻留短字符串,通常是长度少于 20 个字符的字符串。这些短字符串通常会在程序中重复使用,驻留它们可以显著减少内存使用量。

示例:自动驻留短字符串

a = 'short'
 b = 'short' 
print (a is b)   # 输出: True

 m = 'longer_string_that_is_not_interned'
 n = 'longer_string_that_is_not_interned' 
print (m is n)   # 输出: False

在此示例中,短字符串'short'会自动驻留,因此ab引用相同的内存位置。但是,较长的字符串'longer_string_that_is_not_interned'不会自动驻留,因此mn引用不同的内存位置。

手动驻留

对于未自动驻留的字符串,Python 提供了一种使用模块sys.intern()中的函数手动驻留它们的机制sys。当处理较大的字符串或不符合自动驻留标准的字符串时,这很有用。

使用sys.intern()

sys.intern()函数确保相同的字符串共享相同的内存位置,即使它们没有被 Python 自动驻留。

示例:手动驻留sys.intern()

import sys

a = 'unique_string'
 b = 'unique_string' 
print (a is b)   # 输出:False

 a = sys.intern( 'unique_string' ) 
b = sys.intern( 'unique_string' ) 
print (a is b)   # 输出:True

在此示例中,字符串'unique_string'不会自动驻留,因此ab最初引用不同的内存位置。使用之后sys.intern()a和都b引用相同的内存位置,这表明字符串已被手动驻留。

编译期间驻留

Python 还会在编译过程中驻留字符串,尤其是那些出现在函数定义和类定义中的字符串。这意味着在编译时创建的字符串通常会被驻留以优化内存使用并提高性能。

示例:编译时字符串驻留

defgreet ():return'hello'a = greet()b= 'hello'print ( a is b)   #输出:True
     



在此示例中,字符串'hello'在函数编译期间被驻留greet。因此,a和都b引用相同的内存位置。

字符串驻留的含义

字符串驻留会对内存使用和性能产生重大影响。通过了解 Python 何时以及如何驻留字符串,开发人员可以编写更高效、更优化的代码。

内存使用情况

通过确保相同的字符串仅存储一次,驻留字符串可以减少程序的总体内存占用。这对于处理大量重复字符串值的应用程序尤其有益。

示例:通过 Interning 节省内存

import sys 

str_list = [sys.intern( 'repeat' ) for _ in  range ( 1000 )] 
print (str_list[ 0 ] is str_list[ 999 ])   # 输出:True

在此示例中,使用sys.intern()确保字符串的所有 1000 个实例都'repeat'引用相同的内存位置,从而节省大量内存。

性能改进

内置字符串允许更快的比较,因为它们启用了指针相等性检查,而不是逐个字符的比较。这可以在字符串比较是关键操作的应用程序中带来明显的性能提升。

示例:使用 Interning 进行更快的字符串比较

a = sys.intern( 'compare_me' ) 
b = sys.intern( 'compare_me' ) 

if a is b: 
    print ( '字符串相同(快速比较)' ) 
else : 
    print ( '字符串不相同' )

a在这个例子中,和之间的比较b很快,因为它涉及检查它们的内存地址。如果字符串没有被驻留,比较将涉及检查每个字符,这会更慢。

字符串驻留发生的场景

Python 中的字符串驻留并不总是可预测的,但在某些情况下它经常发生。识别这些场景可以帮助您有效利用字符串驻留来优化内存使用和性能。

短字符串和标识符

Python 默认会保留短字符串和标识符。标识符是可用作变量名的字符串,例如字母数字字符串和下划线。短字符串(通常少于 20 个字符)也会自动保留。

示例:Interned 标识符

a = 'name'
 b = 'name' 
print (a is b)   # 输出:True

 x = 'name_1'
 y = 'name_1' 
print (x is y)   # 输出:True

在这些示例中,字符串namename_1被保留,因为它们看起来像标识符,并且由字母数字字符和下划线组成。因此,ab引用相同的内存位置,就像x和 一样y

编译时创建的字符串

在编译时创建的字符串(例如函数定义中使用的字符串)通常会被驻留。这是因为 Python 将源代码编译为字节码,在此过程中,某些字符串会被驻留以优化内存使用并提高性能。

示例:编译时字符串

defgreet ():return'hello'a = greet()b= 'hello'print ( a is b)   #输出:True
     



hello在此示例中,函数返回的字符串greet在函数编译期间被驻留。因此,a和都b引用相同的内存位置。

明确驻留sys.intern()

对于未自动驻留的字符串,您可以使用该sys.intern()方法显式地驻留它们。这对于较长或不符合自动驻留标准但仍在程序中频繁使用或比较的字符串特别有用。

示例:显式驻留

导入系统

a = '唯一字符串'
 b = '唯一字符串' 
print (a is b)   # 输出:False

 a = sys.intern( '唯一字符串' ) 
b = sys.intern( '唯一字符串' ) 
print (a is b)   # 输出:True

在此示例中,字符串unique string不会自动驻留,因此ab最初引用不同的内存位置。使用之后sys.intern()a和都b引用相同的内存位置,这表明字符串已被手动驻留。

大量字符串

在应用程序处理大量字符串的场景中(例如处理文本数据、解析文件或处理大型数据集),字符串驻留可以显著节省内存并提高性能。通过驻留重复的字符串,您可以减少总体内存占用并加快字符串比较操作的速度。

import sys 

words = [ 'interned_word' ] * 1000
 interned_words = [sys.intern(word) for word in words] 

print (interned_words[ 0 ] is interned_words[ 999 ])   # 输出:True

在此示例中,列表words包含 1000 个字符串实例interned_word。通过使用sys.intern(),字符串的所有实例都将被保留,从而节省大量内存。因此,列表的第一个和最后一个元素interned_words引用相同的内存位置。

缓存和记忆

缓存和记忆技术通常涉及存储昂贵的函数调用的结果以避免冗余计算。在这些情况下,字符串驻留可以减少内存使用量并加快缓存字符串的比较速度,从而大有裨益。

示例:使用 Interned 字符串进行缓存

导入系统

缓存 = {} 

def  expensive_function(param):
    param = sys.intern(param)
    如果缓存中的参数:
        返回缓存[param]
    结果= compute_expensive_result(param)
    缓存[param] = result
    返回结果

在此示例中,在检查缓存之前,expensive_function先实习字符串。这可确保相同的字符串引用相同的内存位置,从而使缓存查找更加高效。param

性能关键型应用程序

在性能至关重要的应用程序中,例如那些需要频繁进行字符串比较或在内存受限的环境中运行的应用程序,字符串驻留可以带来巨大的好处。通过驻留字符串,您可以优化内存使用率和字符串操作的速度。

示例:性能关键型字符串比较

导入系统

a = sys.intern( 'performance' ) 
b = sys.intern( 'performance' )

如果a是b:
    print ( '字符串相同(快速比较)' ) 
else:
    print ( '字符串不相同' )

a在这个例子中,和之间的比较b很快,因为它涉及检查它们的内存地址。如果字符串没有被驻留,比较将涉及检查每个字符,这会更慢。

结论

Python 中的字符串驻留是一种强大的优化技术,通过仅存储相同的不可变字符串的一个副本来提高内存效率和性能。通过自动驻留标识符和短字符串,Python 可以节省内存并加快字符串比较速度。sys.intern()对于不适用自动驻留的场景,开发人员还可以使用该函数手动驻留字符串。

了解字符串驻留发生的方式和时间可以帮助您做出明智的决策来优化 Python 代码,尤其是在处理大量字符串、性能关键操作和内存受限环境的应用程序中。通过正确利用字符串驻留,您可以确保您的程序运行得更高效并更好地利用可用资源。

相关推荐

面试官:来,讲一下枚举类型在开发时中实际应用场景!

一.基本介绍枚举是JDK1.5新增的数据类型,使用枚举我们可以很好的描述一些特定的业务场景,比如一年中的春、夏、秋、冬,还有每周的周一到周天,还有各种颜色,以及可以用它来描述一些状态信息,比如错...

一日一技:11个基本Python技巧和窍门

1.两个数字的交换.x,y=10,20print(x,y)x,y=y,xprint(x,y)输出:102020102.Python字符串取反a="Ge...

Python Enum 技巧,让代码更简洁、更安全、更易维护

如果你是一名Python开发人员,你很可能使用过enum.Enum来创建可读性和可维护性代码。今天发现一个强大的技巧,可以让Enum的境界更进一层,这个技巧不仅能提高可读性,还能以最小的代价增...

Python元组编程指导教程(python元组的概念)

1.元组基础概念1.1什么是元组元组(Tuple)是Python中一种不可变的序列类型,用于存储多个有序的元素。元组与列表(list)类似,但元组一旦创建就不能修改(不可变),这使得元组在某些场景...

你可能不知道的实用 Python 功能(python有哪些用)

1.超越文件处理的内容管理器大多数开发人员都熟悉使用with语句进行文件操作:withopen('file.txt','r')asfile:co...

Python 2至3.13新特性总结(python 3.10新特性)

以下是Python2到Python3.13的主要新特性总结,按版本分类整理:Python2到Python3的重大变化Python3是一个不向后兼容的版本,主要改进包括:pri...

Python中for循环访问索引值的方法

技术背景在Python编程中,我们经常需要在循环中访问元素的索引值。例如,在处理列表、元组等可迭代对象时,除了要获取元素本身,还需要知道元素的位置。Python提供了多种方式来实现这一需求,下面将详细...

Python enumerate核心应用解析:索引遍历的高效实践方案

喜欢的条友记得关注、点赞、转发、收藏,你们的支持就是我最大的动力源泉。根据GitHub代码分析统计,使用enumerate替代range(len())写法可减少38%的索引错误概率。本文通过12个生产...

Python入门到脱坑经典案例—列表去重

列表去重是Python编程中常见的操作,下面我将介绍多种实现列表去重的方法,从基础到进阶,帮助初学者全面掌握这一技能。方法一:使用集合(set)去重(最简单)pythondefremove_dupl...

Python枚举类工程实践:常量管理的标准化解决方案

本文通过7个生产案例,系统解析枚举类在工程实践中的应用,覆盖状态管理、配置选项、错误代码等场景,适用于Web服务开发、自动化测试及系统集成领域。一、基础概念与语法演进1.1传统常量与枚举类对比#传...

让Python枚举更强大!教你玩转Enum扩展

为什么你需要关注Enum?在日常开发中,你是否经常遇到这样的代码?ifstatus==1:print("开始处理")elifstatus==2:pri...

Python枚举(Enum)技巧,你值得了解

枚举(Enum)提供了更清晰、结构化的方式来定义常量。通过为枚举添加行为、自动分配值和存储额外数据,可以提升代码的可读性、可维护性,并与数据库结合使用时,使用字符串代替数字能简化调试和查询。Pytho...

78行Python代码帮你复现微信撤回消息!

来源:悟空智能科技本文约700字,建议阅读5分钟。本文基于python的微信开源库itchat,教你如何收集私聊撤回的信息。[导读]Python曾经对我说:"时日不多,赶紧用Python"。于是看...

登录人人都是产品经理即可获得以下权益

文章介绍如何利用Cursor自动开发Playwright网页自动化脚本,实现从选题、写文、生图的全流程自动化,并将其打包成API供工作流调用,提高工作效率。虽然我前面文章介绍了很多AI工作流,但它们...

Python常用小知识-第二弹(python常用方法总结)

一、Python中使用JsonPath提取字典中的值JsonPath是解析Json字符串用的,如果有一个多层嵌套的复杂字典,想要根据key和下标来批量提取value,这是比较困难的,使用jsonpat...

取消回复欢迎 发表评论: