Hướng dẫn where are python strings stored? - chuỗi python được lưu trữ ở đâu?

Tôi đến từ nền C và một người mới bắt đầu trong Python. Tôi muốn biết làm thế nào các chuỗi thực sự được lưu trữ trong bộ nhớ trong trường hợp Python.

Tôi đã làm một cái gì đó giống như

s="foo"

id[s]=140542718184424

id[s[0]]= 140542719027040
id[s[1]]= 140542718832152
id[s[2]]= 140542718832152

Tôi không hiểu làm thế nào mỗi ký tự được lưu trữ trong bộ nhớ và tại sao ID của S không bằng ID của S [0] [giống như nó được sử dụng trong C] và tại sao ID của S1 và S2 lại giống nhau?

Đã hỏi ngày 7 tháng 10 năm 2013 lúc 11:46Oct 7, 2013 at 11:46

3

Python không có nhân vật. Lập chỉ mục vào một chuỗi tạo ra một chuỗi mới, [giống như mọi đối tượng khác] kịp thời biến mất nếu bạn không giữ một tham chiếu đến nó xung quanh. Vì vậy, các ____99 trong ví dụ của bạn không thể được so sánh với nhau, ID của một đối tượng chỉ duy nhất miễn là đối tượng sống. Cụ thể,

s = 'hello world'
s[0]
s[7] 
0 vì trước đây là một đối tượng mới [tạm thời] và
s = 'hello world'
s[0]
s[7] 
1 vì sau khi toán hạng đầu tiên được đánh giá, chuỗi tạm thời đầu tiên bị phá hủy và chuỗi tạm thời thứ hai được phân bổ cho bộ nhớ được giải phóng trước đó. Sau này là một chi tiết thực hiện và một sự trùng hợp ngẫu nhiên và không thể dựa vào.

Lý do về bộ nhớ chuỗi còn phức tạp hơn bởi các chi tiết thực hiện như các chuỗi nhỏ [cùng với số nguyên, một số bộ dữ ].

Đã trả lời ngày 7 tháng 10 năm 2013 lúc 11:54Oct 7, 2013 at 11:54

1

Bài viết này là một bài đọc tốt giải thích cách lưu trữ chuỗi. Tóm tắt:

Khi làm việc với các chuỗi trống hoặc chuỗi ASCII của một nhân vật Python sử dụng thực tập chuỗi. Các chuỗi thực tập hoạt động như một người độc thân, nghĩa là, nếu bạn có hai chuỗi giống hệt nhau được thực tập, chỉ có một bản sao trong số chúng trong bộ nhớ.

Python không UTF-8 trong nội bộ để cung cấp quyền truy cập không đổi vào các chất nền:

s = 'hello world'
s[0]
s[7] 

Cả hai không yêu cầu quét chuỗi từ char ban đầu [hoặc, chính xác hơn là chuỗi con đầu tiên có độ dài 1] đến vị trí

s = 'hello world'
s[0]
s[7] 
3.

Đây là lý do tại sao Python sử dụng ba loại biểu diễn bên trong cho các chuỗi unicode với 1, 2 hoặc 4 byte [s] mỗi char [Latin-1, UCS-2, mã hóa UCS-4] và không sử dụng UTF- được tối ưu hóa không gian số 8.

Đã trả lời ngày 15 tháng 2 năm 2021 lúc 22:37Feb 15, 2021 at 22:37

Đây là phụ thuộc vào việc thực hiện, nhưng một số triển khai [không chỉ của Python, các ngôn ngữ khác cũng có thể giữ một tập hợp các giá trị không đổi có kích thước vừa phải xung quanh để sử dụng thường xuyên. Trong trường hợp của Python, đó có thể là các giá trị như

s = 'hello world'
s[0]
s[7] 
4,
s = 'hello world'
s[0]
s[7] 
5,
s = 'hello world'
s[0]
s[7] 
6,
s = 'hello world'
s[0]
s[7] 
7,
s = 'hello world'
s[0]
s[7] 
8, v.v. Theo cách này, khi một trong những giá trị phổ biến đó là cần thiết, không có chi phí nào để tạo ra nó-chỉ đề cập đến giá trị hiện có.

Đã trả lời ngày 7 tháng 10 năm 2013 lúc 11:54Oct 7, 2013 at 11:54

Bài viết này là một bài đọc tốt giải thích cách lưu trữ chuỗi. Tóm tắt:John Zwinck

Khi làm việc với các chuỗi trống hoặc chuỗi ASCII của một nhân vật Python sử dụng thực tập chuỗi. Các chuỗi thực tập hoạt động như một người độc thân, nghĩa là, nếu bạn có hai chuỗi giống hệt nhau được thực tập, chỉ có một bản sao trong số chúng trong bộ nhớ.33 gold badges309 silver badges421 bronze badges

Kể từ Python 3, loại

s = 'hello world'
s[0]
s[7] 
9 sử dụng biểu diễn Unicode. Các chuỗi Unicode có thể mất tới 4 byte trên mỗi ký tự tùy thuộc vào mã hóa, đôi khi có thể tốn kém từ góc độ bộ nhớ.

Để giảm mức tiêu thụ bộ nhớ và cải thiện hiệu suất, Python sử dụng ba loại biểu diễn bên trong cho chuỗi Unicode:

  • 1 byte mỗi char [mã hóa Latin-1]
  • 2 byte mỗi char [mã hóa UCS-2]
  • 4 byte mỗi char [mã hóa UCS-4]

Khi lập trình trong Python, tất cả các chuỗi đều hoạt động như nhau, và hầu hết thời gian chúng tôi không nhận thấy bất kỳ sự khác biệt nào. Tuy nhiên, sự khác biệt có thể rất đáng chú ý và đôi khi bất ngờ khi làm việc với số lượng lớn văn bản.

Để xem sự khác biệt trong các biểu diễn bên trong, chúng ta có thể sử dụng hàm

>>> import sys
>>> string = 'hello'
>>> sys.getsizeof[string]
54
>>> # 1-byte encoding
>>> sys.getsizeof[string+'!']-sys.getsizeof[string]
1
>>> # 2-byte encoding
>>> string2  = '你'
>>> sys.getsizeof[string2+'好']-sys.getsizeof[string2]
2
>>> sys.getsizeof[string2]
76
>>> # 4-byte encoding
>>> string3 = '🐍'
>>> sys.getsizeof[string3+'💻']-sys.getsizeof[string3]
4
>>> sys.getsizeof[string3]
80
0, trả về kích thước của một đối tượng trong byte:

>>> import sys
>>> string = 'hello'
>>> sys.getsizeof[string]
54
>>> # 1-byte encoding
>>> sys.getsizeof[string+'!']-sys.getsizeof[string]
1
>>> # 2-byte encoding
>>> string2  = '你'
>>> sys.getsizeof[string2+'好']-sys.getsizeof[string2]
2
>>> sys.getsizeof[string2]
76
>>> # 4-byte encoding
>>> string3 = '🐍'
>>> sys.getsizeof[string3+'💻']-sys.getsizeof[string3]
4
>>> sys.getsizeof[string3]
80

Như bạn có thể thấy, tùy thuộc vào nội dung của một chuỗi, Python sử dụng các mã hóa khác nhau. Lưu ý rằng mỗi chuỗi trong Python có thêm 49-80 byte bộ nhớ, trong đó nó lưu trữ thông tin bổ sung, chẳng hạn như băm, độ dài, độ dài trong byte, loại mã hóa và cờ chuỗi. Đó là lý do tại sao một chuỗi trống mất 49 byte bộ nhớ.

Chúng ta có thể truy xuất mã hóa trực tiếp từ một đối tượng bằng cách sử dụng

>>> import sys
>>> string = 'hello'
>>> sys.getsizeof[string]
54
>>> # 1-byte encoding
>>> sys.getsizeof[string+'!']-sys.getsizeof[string]
1
>>> # 2-byte encoding
>>> string2  = '你'
>>> sys.getsizeof[string2+'好']-sys.getsizeof[string2]
2
>>> sys.getsizeof[string2]
76
>>> # 4-byte encoding
>>> string3 = '🐍'
>>> sys.getsizeof[string3+'💻']-sys.getsizeof[string3]
4
>>> sys.getsizeof[string3]
80
1:

import ctypes

class PyUnicodeObject[ctypes.Structure]:
    # internal fields of the string object
    _fields_ = [["ob_refcnt", ctypes.c_long],
                ["ob_type", ctypes.c_void_p],
                ["length", ctypes.c_ssize_t],
                ["hash", ctypes.c_ssize_t],
                ["interned", ctypes.c_uint, 2],
                ["kind", ctypes.c_uint, 3],
                ["compact", ctypes.c_uint, 1],
                ["ascii", ctypes.c_uint, 1],
                ["ready", ctypes.c_uint, 1],
                # ...
                # ...
                ]


def get_string_kind[string]:
    return PyUnicodeObject.from_address[id[string]].kind

>>> get_string_kind['Hello']
1
>>> get_string_kind['你好']
2
>>> get_string_kind['🐍']
4

Nếu tất cả các ký tự trong một chuỗi có thể phù hợp với phạm vi ASCII, thì chúng được mã hóa bằng mã hóa Latin-1 1 byte. Về cơ bản, Latin-1 đại diện cho 256 ký tự Unicode đầu tiên. Nó hỗ trợ nhiều ngôn ngữ Latin, như tiếng Anh, tiếng Thụy Điển, tiếng Ý, tiếng Na Uy, v.v. Tuy nhiên, nó không thể lưu trữ các ngôn ngữ không phải là tiếng Latin, như tiếng Trung, tiếng Nhật, tiếng Do Thái, cyrillic. Đó là bởi vì các điểm mã hóa của chúng [chỉ mục số] được xác định bên ngoài phạm vi 1 byte [0-255].

>>> ord['a']
97
>>> ord['你']
20320
>>> ord['!']
33

Hầu hết các ngôn ngữ tự nhiên phổ biến có thể phù hợp với mã hóa 2 byte [UCS-2]. Mã hóa 4 byte [UCS-4] được sử dụng khi một chuỗi chứa các ký hiệu đặc biệt, biểu tượng cảm xúc hoặc ngôn ngữ hiếm. Có gần 300 khối [phạm vi] trong tiêu chuẩn Unicode. Bạn có thể tìm thấy các khối 4 byte sau khối 0xffff.

Giả sử chúng ta có 10GB văn bản ASCII và chúng ta muốn tải nó trong bộ nhớ. Nếu bạn chèn một biểu tượng cảm xúc duy nhất vào văn bản của chúng tôi, kích thước của một chuỗi sẽ tăng theo hệ số 4! Đây là một sự khác biệt rất lớn mà bạn có thể gặp phải trong thực tế khi làm việc với các vấn đề NLP.

Tại sao Python không sử dụng mã hóa UTF-8 bên trong

Mã hóa Unicode nổi tiếng và phổ biến nhất là UTF-8, nhưng Python không sử dụng nó trong nội bộ.

Khi một chuỗi được lưu trữ trong mã hóa UTF-8, mỗi ký tự được mã hóa bằng 1-4 byte tùy thuộc vào ký tự mà nó đại diện. Đó là một mã hóa hiệu quả lưu trữ, nhưng nó có một bất lợi đáng kể. Vì mỗi ký tự có thể thay đổi chiều dài của byte, không có cách nào để truy cập ngẫu nhiên một ký tự cá nhân theo chỉ mục mà không cần quét chuỗi. Vì vậy, để thực hiện một thao tác đơn giản, chẳng hạn như

>>> import sys
>>> string = 'hello'
>>> sys.getsizeof[string]
54
>>> # 1-byte encoding
>>> sys.getsizeof[string+'!']-sys.getsizeof[string]
1
>>> # 2-byte encoding
>>> string2  = '你'
>>> sys.getsizeof[string2+'好']-sys.getsizeof[string2]
2
>>> sys.getsizeof[string2]
76
>>> # 4-byte encoding
>>> string3 = '🐍'
>>> sys.getsizeof[string3+'💻']-sys.getsizeof[string3]
4
>>> sys.getsizeof[string3]
80
2 với UTF-8 Python sẽ cần quét một chuỗi cho đến khi nó tìm thấy một ký tự bắt buộc. Mã hóa chiều dài cố định không có vấn đề như vậy, để định vị một ký tự bằng chỉ mục Python chỉ nhân số chỉ số với độ dài của một ký tự [1, 2 hoặc 4 byte].

Chuỗi thực tập

Khi làm việc với các chuỗi trống hoặc chuỗi ASCII của một nhân vật Python sử dụng thực tập chuỗi. Các chuỗi thực tập hoạt động như một người độc thân, nghĩa là, nếu bạn có hai chuỗi giống hệt nhau được thực tập, chỉ có một bản sao trong số chúng trong bộ nhớ.

>>> a = 'hello'
>>> b = 'world'
>>> a[4],b[1]
['o', 'o']
>>> id[a[4]], id[b[1]], a[4] is b[1]
[4567926352, 4567926352, True]
>>> id['']
4545673904
>>> id['']
4545673904

Như bạn có thể thấy, cả hai lát chuỗi chỉ vào cùng một địa chỉ trong bộ nhớ. Điều đó là có thể vì chuỗi Python là bất biến.

Trong Python, việc thực tập chuỗi không bị giới hạn thành các ký tự hoặc chuỗi trống. Các chuỗi được tạo trong quá trình biên dịch mã cũng có thể được thực tập nếu độ dài của chúng không vượt quá 20 ký tự.

Điêu nay bao gôm:

  • Tên chức năng và tên lớp
  • Tên biến
  • Tên đối số
  • Hằng số [tất cả các chuỗi được xác định trong mã]
  • Chìa khóa của từ điển
  • Tên của các thuộc tính

Khi bạn nhấn enter in python replin, câu lệnh của bạn sẽ được biên dịch xuống mã byte. Đó là lý do tại sao tất cả các chuỗi ngắn trong repred cũng được thực tập.

>>> a = 'teststring'
>>> b = 'teststring'
>>> id[a], id[b], a is b
[4569487216, 4569487216, True]
>>> a = 'test'*5
>>> b = 'test'*5
>>> len[a], id[a], id[b], a is b
[20, 4569499232, 4569499232, True]
>>> a = 'test'*6
>>> b = 'test'*6
>>> len[a], id[a], id[b], a is b
[24, 4569479328, 4569479168, False]

Ví dụ này sẽ không hoạt động, bởi vì các chuỗi như vậy không phải là hằng số:

>>> open['test.txt','w'].write['hello']
5
>>> open['test.txt','r'].read[]
'hello'
>>> a = open['test.txt','r'].read[]
>>> b = open['test.txt','r'].read[]
>>> id[a], id[b], a is b
[4384934576, 4384934688, False]
>>> len[a], id[a], id[b], a is b
[5, 4384934576, 4384934688, False]

Kỹ thuật thực tập chuỗi tiết kiệm hàng chục ngàn phân bổ chuỗi trùng lặp. Trong nội bộ, việc thực tập chuỗi được duy trì bởi một từ điển toàn cầu nơi các chuỗi được sử dụng làm khóa. Để kiểm tra xem đã có một chuỗi giống hệt nhau trong bộ nhớ Python thực hiện hoạt động thành viên từ điển.

Đối tượng Unicode là gần 16 000 dòng mã C, do đó có rất nhiều tối ưu hóa nhỏ không được đề cập trong bài viết này. Nếu bạn muốn tìm hiểu thêm về Unicode trong Python, tôi sẽ khuyên bạn nên đọc PEP về chuỗi và kiểm tra mã của đối tượng Unicode.

Làm thế nào để Python lưu trữ chuỗi nội bộ?

TL; DR: Cpython lưu trữ các chuỗi dưới dạng chuỗi các ký tự Unicode. Các ký tự Unicode được lưu trữ với 1, 2 hoặc 4 byte tùy thuộc vào kích thước mã hóa của chúng. Kích thước byte của các chuỗi tăng theo tỷ lệ theo kích thước của ký tự lớn nhất của nó, vì tất cả các ký tự phải có cùng kích thước.CPython stores strings as sequences of unicode characters. Unicode characters are stored with either 1, 2, or 4 bytes depending on the size of their encoding. Byte size of strings increases proportionally with the size of its largest character, since all characters must be of the same size.

Các chuỗi được lưu trữ trong Python 3 ở đâu?

Các chuỗi được lưu trữ bên trong như thế nào trong Python 3?Chúng được lưu trữ nội bộ như một chuỗi Unicode với một codec biết.Điều đó có nghĩa là chúng là một chuỗi các byte trong đó mỗi ký tự có thể là một, hai, ba hoặc bốn byte tùy thuộc vào trang unicode mà các ký tự này đến từ.internally as a Unicode sequence with a know codec. That means that they are a sequence of bytes where each character might be one, two, three or four bytes depending on which Unicode page this characters are from.

Các chuỗi được lưu trữ trong Python 2 như thế nào?

Python 2 sử dụng loại str để lưu trữ byte và loại unicode để lưu trữ các điểm mã Unicode.Tất cả các chuỗi theo mặc định là loại str - đó là byte ~ và mã hóa mặc định là ASCII.Vì vậy, nếu một tệp đến là các ký tự cyrillic, Python 2 có thể thất bại vì ASCII sẽ không thể xử lý các ký tự cyrillic đó.str type to store bytes and unicode type to store unicode code points. All strings by default are str type — which is bytes~ And Default encoding is ASCII. So if an incoming file is Cyrillic characters, Python 2 might fail because ASCII will not be able to handle those Cyrillic Characters.

Các chuỗi có được lưu trữ trong bộ nhớ không?

Chuỗi được lưu trữ trên khu vực heap ở một vị trí bộ nhớ riêng biệt được gọi là nhóm không đổi chuỗi.Nhóm không đổi chuỗi: Đây là một khối bộ nhớ riêng biệt trong đó tất cả các biến chuỗi được giữ.Chuỗi str1 = "Xin chào";Trực tiếp, sau đó JVM tạo một đối tượng chuỗi với giá trị đã cho trong một nhóm không đổi chuỗi.. String constant pool: It is a separate block of memory where all the String variables are held. String str1 = "Hello"; directly, then JVM creates a String object with the given value in a String constant pool.

Bài Viết Liên Quan

Chủ Đề