python打印内存的值-分析内存中字符串以及编码后的值

本文深入解析Python3中字符串(str)与字节串(bytes)的区别,探讨字符集与编码的关系,尤其关注unicode与utf8编码。通过实例展示字符串内部存储机制及不同编码方式下字节串的变化。

字符串和字符串编码是两个不同的概念,python作为一门优秀的编程语言中是做了严格的区分,即使用不同的class来表示,同时存储的内容也是不一样的。尽管在python2中区分的还不是特别的明显,但是在python3中是明确的使用str类表示字符串;bytes表示字节串,即可以用来存储字符串编码后的值,说明如下:

首先字符集和字符编码在ASCII,GB2312,GBK中往往混淆这两个概念,因为他们即是字符集也是字符编码,这是编码早期阶段遗留的问题;但是unicode字符集的庞大,使得其产生了诸多编码方式,包括utf8,utf16,utf32等多种编码方式,因此在unicode中需要明确字符集和编码的不同。通常来说,unicode指的是字符集,对应字符的编号;utf8指的是unicode对应的编码。关于utf8编码规则,我在这篇文中有详细的介绍;关于unicode的应用,我在这里有介绍,可以自行查看。

1,Python3中使用str类来表示和存储字符串,在一个具体的字符串对象中存储的内容是每个字符的编号,该编号就是字符集中赋予的。至于该编号使用几个字节来进行存储往往是不确定的,例如常用汉字的编号通常使用两个字节就可以表示编号。对于一些特殊的字符(比如音乐中的那些字符),往往需要更多的字节。这是python 内部的实现机制,不在过多的阐述,感兴趣的同学在学习完本文方法文后,自行研究尝试。

2,Python3中使用bytes类来表示和存储字符串的编码。由于unicode字符集对应的编码方式不止一个,包括utf8,ut16,utf32等等,python通常默认时使用utf8编码方式。因此不同的编码方式下,得到字符串的编码值:1,首先互不相同;2,其次编码之后bytes对象中存储的值和str对象中存储的值也是不一样的。

以我的优快云博客名称 村中少年这几个字符串为例:
1,首先这几个字符的unicode编号分别为6751,4E2D,5C11,5E74
2,Utf8编码后的值为E6 9D 91 E4 B8 AD E5 B0 91 E5 B9 B4

编写如下程序,并查看对象对应的内存内容:

def printMem(data):
    from ctypes import string_at
    from sys import getsizeof
    from binascii import hexlify

    print(hexlify(string_at(id(data), getsizeof(data))))
if __name__ == "__main__":
    
    nameStr = '村中少年'
    nameBytes = nameStr.encode()
    print(type(nameStr))
    print(type(nameBytes))
    printMem(nameStr)
    printMem(nameBytes)

运行结果如下:
<class ‘str’>
<class ‘bytes’>
b’0500000000000000c0f562b5417f000004000000000000001a53594dc9e6e066a80a64b5417f0000000000000000000000000000000000000000000000000000000000000000000051672d4e115c745e0000’
b’0300000000000000e0fe60b5417f00000c00000000000000ffffffffffffffffe69d91e4b8ade5b091e5b9b400’

标记的部分分别表示的是字符串中的unicode编号以及utf8编码后的值,可以看到nameStr字符串中的确存储了Unicode编号的值,nameBytes存储的是编码后的值,验证了一开始所说的。

为什么要使用编号表示字符串本身呢?因为字符串,无论在何处,无论是写在纸上还是显示在计算机上,其本身的含义不变,因此需要编号这个确定的值来表示。但是在存储的时候,出于效率的考虑,有不同的编码方式,不同的编码方式意味这不同的值。因此编码值来表示字符串是不合适的,编码值只是存储层次的表示。通过我的这篇文章,相信你对于字符串和其编码方式应该能够加以区分。

本文为优快云村中少年原创文章,转载记得加上小尾巴偶,博主链接这里

### 字符串编码原理 在 Python 中,字符串本质上是以 Unicode 编码存储的字符序列。这意味着无论源文本使用的是哪种字符集(如 ASCII、GBK 或 UTF-8),在程序运行时,Python 会将其转换为统一的 Unicode 格式进行处理。这种设计简化了多语言文本的处理,使得字符串可以在不同语言和平台之间无缝传输和操作[^3]。 Unicode 是一种通用的字符编码标准,它为世界上几乎所有的字符都分配了唯一的编号。然而,Unicode 本身并不规定如何将这些字符编号转化为字节进行存储和传输。因此,UTF-8 成为了最常用的 Unicode 编码实现方式,它采用可变长度的编码方式,对 ASCII 字符仅使用一个字节,而对其他字符则使用更多字节。这种设计在保证兼容性的同时,也节省了存储空间[^2]。 ### 字符串编码与解码 在实际应用中,字符串通常需要在不同的编码格式之间转换。Python 提供了 `encode()` 和 `decode()` 方法来实现这一过程。`encode()` 方法用于将字符串转换为特定编码的字节序列,而 `decode()` 则用于将字节序列还原为字符串。例如: ```python s = "你好,世界" # 将字符串编码为 UTF-8 格式的字节序列 encoded = s.encode("utf-8") # 将字节序列解码回字符串 decoded = encoded.decode("utf-8") ``` 需要注意的是,在进行编码和解码操作时,必须确保使用相同的编码格式,否则可能导致数据损坏或解码错误。此外,如果原始字符串中包含无法用目标编码表示的字符,则 `encode()` 操作会抛出异常,除非指定 `errors` 参数以定义替代处理方式,例如忽略无法编码的字符或使用替代符号表示。 ### 字符串的内部存储与显示 Python内存中始终以 Unicode 编码存储字符串,这意味着无论输入数据的原始编码如何,都会在程序内部统一处理为 Unicode。然而,当字符串打印或显示时,Python 会根据当前环境的默认编码设置进行输出。例如,在终端或控制台中打印字符串时,其实际显示的字符取决于终端的编码配置。如果终端使用 UTF-8 编码,则 Unicode 字符可以正常显示;否则可能会出现乱码[^3]。 当字符串被放入列表或其他容器中并打印时,Python 会显示其原始的 Unicode 编码形式,而不是实际字符。这种行为反映了字符串内存中的存储方式,有助于调试和分析编码问题。例如: ```python s = "你好" print([s]) # 输出:['\u4f60\u597d'] ``` ### 字符串编码处理的常见问题与解决方案 在处理多语言文本、文件读写或网络通信时,编码问题尤为常见。以下是一些常见的编码处理场景及建议: 1. **文件读写中的编码处理**:在打开文件时,应明确指定文件的编码格式,以避免因默认编码不一致导致的解码错误。例如: ```python with open("file.txt", "r", encoding="utf-8") as f: content = f.read() ``` 2. **网络请求中的编码处理**:从网络获取的数据通常需要根据响应头中的 `Content-Type` 字段确定其编码格式。如果响应中未明确指定编码,则可以尝试使用默认(如 UTF-8)进行解码,或者通过分析响应内容猜测编码方式。 3. **多语言文本处理**:在处理包含多种语言的文本时,应优先使用 UTF-8 编码,因为它支持广泛的字符集,并具有良好的兼容性。如果必须使用其他编码格式,则应在程序中统一转换为 Unicode,以避免编码冲突。 4. **异常处理与容错机制**:在进行编码转换时,应使用 `errors` 参数定义容错策略,以避免程序因编码错误而中断。例如,使用 `errors='ignore'` 可以忽略无法编码的字符,而 `errors='replace'` 则会用替代字符(如 `?`)替换无法编码的部分。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

村中少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值