python 字符串驻留机制

偶然发现一个python字符串的现象:

>>> a = '123_abc'

>>> b = '123_abc'

>>> a is b

True

>>> c = 'abc#123'

>>> d = 'abc#123'

>>> c is d

False

这是为什么呢,原来它们的id不一样。

>>> id(a) == id(b)

True

>>> id(c) == id(d)

False

那为什么它们的地址有的相同,有的不同呢?查询后得知这是一种 Python 的字符串驻留机制。

字符串驻留机制

也称为字符串常量优化(string interning),是一种在 Python 解释器中自动进行的优化过程。它主要目的是减少内存的使用,提高程序的运行效率。

工作原理

  1. 小字符串:Python 只会对短小的字符串进行驻留。但是,这个长度并不是固定的,它可能会因 Python 的不同版本或实现而有所不同。
  2. 字符串池(String Pool):Python 解释器维护一个字符串池,用于存储所有已经出现过的字符串常量。
  3. 驻留(Interning):当解释器遇到一个新的字符串字面量时,它会首先检查这个字符串是否已经存在于字符串池中。如果存在,则直接使用池中的引用;如果不存在,就将这个字符串添加到池中,并返回这个字符串的引用。
  4. 内存节省:由于相同的字符串字面量在程序中可能被多次使用,通过字符串驻留机制,可以确保这些重复的字符串只存储一次,从而节省内存。
  5. 性能提升:字符串比较操作可以通过比较它们的引用地址来完成,这比逐字符比较要快得多。因此,字符串驻留可以提高字符串比较的性能。
  6. 自动和透明:字符串驻留是自动进行的,程序员不需要显式地进行任何操作。Python 解释器会在后台处理这一过程。
  7. 不可变类型:字符串驻留机制只适用于不可变类型,因为可变类型的对象内容可能会改变,这会使得引用地址比较失去意义。如果字符串可以修改,那么驻留机制可能会导致意外的副作用。
  8. 限制:字符串驻留机制虽然有诸多好处,但也存在一些限制。例如,如果程序中使用了大量的动态生成的字符串,那么字符串驻留可能不会带来太大的好处,因为这些字符串可能不会被重复使用。
  9. 字符串字面量:只有当字符串是字面量时,Python 才会尝试进行驻留。通过其他方式(如 str() 函数、字符串拼接等)创建的字符串通常不会被驻留。
  10. 编译时驻留:字符串驻留是在 Python 源代码编译成字节码时进行的,而不是在运行时。这意味着在运行时动态生成的字符串通常不会被驻留。

显式驻留

Python 提供了一个sys库函数 intern(),允许程序员显式地将一个字符串驻留。使用这个函数可以手动控制字符串的驻留过程:

>>> from sys import intern

>>> s = intern('abc#123')

>>> t = intern('abc#123')

>>> s is t

True

>>> s = 'abc#123'

>>> t = 'abc#123'

>>> s is t

False

>>> a = intern('abc_123')

>>> b = 'abc_123'

>>> a is b

True

字符串长短的分界

小字符串才进行驻留,具体多少长度是界线也没有细查,大概用二分法也能枚举出来。

python 复制代码
>>> x = 'abcdefghijklmnopqrstuvwxyz'*100
>>> y = 'abcdefghijklmnopqrstuvwxyz'*100
>>> x is y
True
>>> x = 'abcdefghijklmnopqrstuvwxyz'*200
>>> y = 'abcdefghijklmnopqrstuvwxyz'*200
>>> x is y
False
>>> x = 'abcdefghijklmnopqrstuvwxyz'*150
>>> y = 'abcdefghijklmnopqrstuvwxyz'*150
>>> x is y
True
>>> x = 'abcdefghijklmnopqrstuvwxyz'*175
>>> y = 'abcdefghijklmnopqrstuvwxyz'*175
>>> x is y
False
......

附:字符串方法

(版本python 3.12)

capitalize(self, /)

Return a capitalized version of the string.

More specifically, make the first character have upper case and the rest lower

case.

casefold(self, /)

Return a version of the string suitable for caseless comparisons.

center(self, width, fillchar=' ', /)

Return a centered string of length width.

Padding is done using the specified fill character (default is a space).

count(...)

S.count(sub[, start[, end]]) -> int

Return the number of non-overlapping occurrences of substring sub in

string S[start:end]. Optional arguments start and end are

interpreted as in slice notation.

encode(self, /, encoding='utf-8', errors='strict')

Encode the string using the codec registered for encoding.

encoding

The encoding in which to encode the string.

errors

The error handling scheme to use for encoding errors.

The default is 'strict' meaning that encoding errors raise a

UnicodeEncodeError. Other possible values are 'ignore', 'replace' and

'xmlcharrefreplace' as well as any other name registered with

codecs.register_error that can handle UnicodeEncodeErrors.

endswith(...)

S.endswith(suffix[, start[, end]]) -> bool

Return True if S ends with the specified suffix, False otherwise.

With optional start, test S beginning at that position.

With optional end, stop comparing S at that position.

suffix can also be a tuple of strings to try.

expandtabs(self, /, tabsize=8)

Return a copy where all tab characters are expanded using spaces.

If tabsize is not given, a tab size of 8 characters is assumed.

find(...)

S.find(sub[, start[, end]]) -> int

Return the lowest index in S where substring sub is found,

such that sub is contained within S[start:end]. Optional

arguments start and end are interpreted as in slice notation.

Return -1 on failure.

format(...)

S.format(*args, **kwargs) -> str

Return a formatted version of S, using substitutions from args and kwargs.

The substitutions are identified by braces ('{' and '}').

format_map(...)

S.format_map(mapping) -> str

Return a formatted version of S, using substitutions from mapping.

The substitutions are identified by braces ('{' and '}').

index(...)

S.index(sub[, start[, end]]) -> int

Return the lowest index in S where substring sub is found,

such that sub is contained within S[start:end]. Optional

arguments start and end are interpreted as in slice notation.

Raises ValueError when the substring is not found.

isalnum(self, /)

Return True if the string is an alpha-numeric string, False otherwise.

A string is alpha-numeric if all characters in the string are alpha-numeric and

there is at least one character in the string.

isalpha(self, /)

Return True if the string is an alphabetic string, False otherwise.

A string is alphabetic if all characters in the string are alphabetic and there

is at least one character in the string.

isascii(self, /)

Return True if all characters in the string are ASCII, False otherwise.

ASCII characters have code points in the range U+0000-U+007F.

Empty string is ASCII too.

isdecimal(self, /)

Return True if the string is a decimal string, False otherwise.

A string is a decimal string if all characters in the string are decimal and

there is at least one character in the string.

isdigit(self, /)

Return True if the string is a digit string, False otherwise.

A string is a digit string if all characters in the string are digits and there

is at least one character in the string.

isidentifier(self, /)

Return True if the string is a valid Python identifier, False otherwise.

Call keyword.iskeyword(s) to test whether string s is a reserved identifier,

such as "def" or "class".

islower(self, /)

Return True if the string is a lowercase string, False otherwise.

A string is lowercase if all cased characters in the string are lowercase and

there is at least one cased character in the string.

isnumeric(self, /)

Return True if the string is a numeric string, False otherwise.

A string is numeric if all characters in the string are numeric and there is at

least one character in the string.

isprintable(self, /)

Return True if the string is printable, False otherwise.

A string is printable if all of its characters are considered printable in

repr() or if it is empty.

isspace(self, /)

Return True if the string is a whitespace string, False otherwise.

A string is whitespace if all characters in the string are whitespace and there

is at least one character in the string.

istitle(self, /)

Return True if the string is a title-cased string, False otherwise.

In a title-cased string, upper- and title-case characters may only

follow uncased characters and lowercase characters only cased ones.

isupper(self, /)

Return True if the string is an uppercase string, False otherwise.

A string is uppercase if all cased characters in the string are uppercase and

there is at least one cased character in the string.

join(self, iterable, /)

Concatenate any number of strings.

The string whose method is called is inserted in between each given string.

The result is returned as a new string.

Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs'

ljust(self, width, fillchar=' ', /)

Return a left-justified string of length width.

Padding is done using the specified fill character (default is a space).

lower(self, /)

Return a copy of the string converted to lowercase.

lstrip(self, chars=None, /)

Return a copy of the string with leading whitespace removed.

If chars is given and not None, remove characters in chars instead.

partition(self, sep, /)

Partition the string into three parts using the given separator.

This will search for the separator in the string. If the separator is found,

returns a 3-tuple containing the part before the separator, the separator

itself, and the part after it.

If the separator is not found, returns a 3-tuple containing the original string

and two empty strings.

removeprefix(self, prefix, /)

Return a str with the given prefix string removed if present.

If the string starts with the prefix string, return string[len(prefix):].

Otherwise, return a copy of the original string.

removesuffix(self, suffix, /)

Return a str with the given suffix string removed if present.

If the string ends with the suffix string and that suffix is not empty,

return string[:-len(suffix)]. Otherwise, return a copy of the original

string.

replace(self, old, new, count=-1, /)

Return a copy with all occurrences of substring old replaced by new.

count

Maximum number of occurrences to replace.

-1 (the default value) means replace all occurrences.

If the optional argument count is given, only the first count occurrences are

replaced.

rfind(...)

S.rfind(sub[, start[, end]]) -> int

Return the highest index in S where substring sub is found,

such that sub is contained within S[start:end]. Optional

arguments start and end are interpreted as in slice notation.

Return -1 on failure.

rindex(...)

S.rindex(sub[, start[, end]]) -> int

Return the highest index in S where substring sub is found,

such that sub is contained within S[start:end]. Optional

arguments start and end are interpreted as in slice notation.

Raises ValueError when the substring is not found.

rjust(self, width, fillchar=' ', /)

Return a right-justified string of length width.

Padding is done using the specified fill character (default is a space).

rpartition(self, sep, /)

Partition the string into three parts using the given separator.

This will search for the separator in the string, starting at the end. If

the separator is found, returns a 3-tuple containing the part before the

separator, the separator itself, and the part after it.

If the separator is not found, returns a 3-tuple containing two empty strings

and the original string.

rsplit(self, /, sep=None, maxsplit=-1)

Return a list of the substrings in the string, using sep as the separator string.

sep

The separator used to split the string.

When set to None (the default value), will split on any whitespace

character (including \n \r \t \f and spaces) and will discard

empty strings from the result.

maxsplit

Maximum number of splits (starting from the left).

-1 (the default value) means no limit.

Splitting starts at the end of the string and works to the front.

rstrip(self, chars=None, /)

Return a copy of the string with trailing whitespace removed.

If chars is given and not None, remove characters in chars instead.

split(self, /, sep=None, maxsplit=-1)

Return a list of the substrings in the string, using sep as the separator string.

sep

The separator used to split the string.

When set to None (the default value), will split on any whitespace

character (including \n \r \t \f and spaces) and will discard

empty strings from the result.

maxsplit

Maximum number of splits (starting from the left).

-1 (the default value) means no limit.

Note, str.split() is mainly useful for data that has been intentionally

delimited. With natural text that includes punctuation, consider using

the regular expression module.

splitlines(self, /, keepends=False)

Return a list of the lines in the string, breaking at line boundaries.

Line breaks are not included in the resulting list unless keepends is given and

true.

startswith(...)

S.startswith(prefix[, start[, end]]) -> bool

Return True if S starts with the specified prefix, False otherwise.

With optional start, test S beginning at that position.

With optional end, stop comparing S at that position.

prefix can also be a tuple of strings to try.

strip(self, chars=None, /)

Return a copy of the string with leading and trailing whitespace removed.

If chars is given and not None, remove characters in chars instead.

swapcase(self, /)

Convert uppercase characters to lowercase and lowercase characters to uppercase.

title(self, /)

Return a version of the string where each word is titlecased.

More specifically, words start with uppercased characters and all remaining

cased characters have lower case.

translate(self, table, /)

Replace each character in the string using the given translation table.

table

Translation table, which must be a mapping of Unicode ordinals to

Unicode ordinals, strings, or None.

The table must implement lookup/indexing via getitem, for instance a

dictionary or list. If this operation raises LookupError, the character is

left untouched. Characters mapped to None are deleted.

upper(self, /)

Return a copy of the string converted to uppercase.

zfill(self, width, /)

Pad a numeric string with zeros on the left, to fill a field of the given width.

The string is never truncated.


目录

字符串驻留机制

工作原理

显式驻留

字符串长短的分界

附:字符串方法


相关推荐
不去幼儿园1 小时前
【MARL】深入理解多智能体近端策略优化(MAPPO)算法与调参
人工智能·python·算法·机器学习·强化学习
幽兰的天空2 小时前
Python 中的模式匹配:深入了解 match 语句
开发语言·python
网易独家音乐人Mike Zhou5 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
安静读书5 小时前
Python解析视频FPS(帧率)、分辨率信息
python·opencv·音视频
小二·7 小时前
java基础面试题笔记(基础篇)
java·笔记·python
小喵要摸鱼8 小时前
Python 神经网络项目常用语法
python
一念之坤10 小时前
零基础学Python之数据结构 -- 01篇
数据结构·python
wxl78122710 小时前
如何使用本地大模型做数据分析
python·数据挖掘·数据分析·代码解释器
NoneCoder10 小时前
Python入门(12)--数据处理
开发语言·python
LKID体11 小时前
Python操作neo4j库py2neo使用(一)
python·oracle·neo4j