


1 Unicode
Unit asas storan komputer ialah bait, yang terdiri daripada 8 bit. Memandangkan bahasa Inggeris hanya terdiri daripada 26 huruf ditambah beberapa simbol, aksara Inggeris boleh disimpan terus dalam bait. Tetapi bahasa lain (seperti Cina, Jepun, Korea, dll.) perlu menggunakan berbilang bait untuk pengekodan kerana bilangan aksara yang banyak.
Dengan penyebaran teknologi komputer, teknologi pengekodan aksara bukan Latin terus berkembang, tetapi masih terdapat dua batasan utama:
Tidak menyokong berbilang bahasa: skema pengekodan satu bahasa tidak boleh digunakan untuk bahasa lain
Tiada standard bersatu: contohnya, bahasa Cina mempunyai GBK, GB2312, GB18030 dan piawaian pengekodan lain
Oleh kerana kaedah pengekodan tidak seragam, pembangun perlu menukar berulang-alik antara pengekodan yang berbeza, dan banyak ralat pasti akan berlaku. Untuk menyelesaikan masalah ketidakkonsistenan seperti ini, standard Unicode telah dicadangkan. Unicode mengatur dan mengekod kebanyakan sistem penulisan di dunia, membolehkan komputer memproses teks dengan cara yang bersatu. Unicode kini mengandungi lebih daripada 140,000 aksara dan secara semula jadi menyokong berbilang bahasa. (Uni Unicode ialah punca “penyatuan”)
2 Unicode dalam Python
2.1 Faedah objek Unicode
Selepas Python 3, Unicode digunakan secara dalaman dalam objek str Mewakili, dan oleh itu menjadi objek Unicode dalam kod sumber. Kelebihan menggunakan perwakilan Unicode ialah logik teras program menggunakan Unicode secara seragam, dan hanya perlu dinyahkod dan dikodkan pada lapisan input dan output, yang boleh mengelakkan pelbagai masalah pengekodan setakat yang paling besar.
Rajah adalah seperti berikut:
2.2 Pengoptimuman Python bagi Unicode
Masalah: Memandangkan Unicode mengandungi lebih daripada 140,000 aksara, setiap A aksara memerlukan sekurang-kurangnya 4 bait untuk disimpan (ini mungkin kerana 2 bait tidak mencukupi, jadi 4 bait digunakan dan 3 bait biasanya tidak digunakan). Kod ASCII untuk aksara Inggeris memerlukan hanya 1 bait Penggunaan Unicode akan menggandakan kos aksara Inggeris yang kerap digunakan.
Pertama, mari kita lihat perbezaan saiz pelbagai bentuk objek str dalam Python:
>>> sys.getsizeof('ab') - sys.getsizeof('a') 1 >>> sys.getsizeof('一二') - sys.getsizeof('一') 2 >>> sys.getsizeof('????????') - sys.getsizeof('????') 4
Dapat dilihat bahawa Python secara dalaman mengoptimumkan objek Unicode: mengikut kandungan teks, unit storan asas dipilih.
Storan asas objek Unicode dibahagikan kepada tiga kategori mengikut julat titik kod Unikod aksara teks:
PyUnicode_1BYTE_KIND: Semua titik kod aksara berada di antara U+ 0000 dan U+00FF
PyUnicode_2BYTE_KIND: Semua titik kod aksara adalah antara U+0000 dan U+FFFF, dan sekurang-kurangnya satu aksara mempunyai titik kod lebih besar daripada U+00FF
-
PyUnicode_1BYTE_KIND: Semua titik kod aksara adalah antara U+0000 dan U+10FFFF, dan sekurang-kurangnya satu aksara mempunyai titik kod lebih besar daripada U+FFFF
Penghitungan yang sepadan adalah seperti berikut:
enum PyUnicode_Kind { /* String contains only wstr byte characters. This is only possible when the string was created with a legacy API and _PyUnicode_Ready() has not been called yet. */ PyUnicode_WCHAR_KIND = 0, /* Return values of the PyUnicode_KIND() macro: */ PyUnicode_1BYTE_KIND = 1, PyUnicode_2BYTE_KIND = 2, PyUnicode_4BYTE_KIND = 4 };
Pilih unit storan yang berbeza mengikut klasifikasi yang berbeza:
/* Py_UCS4 and Py_UCS2 are typedefs for the respective unicode representations. */ typedef uint32_t Py_UCS4; typedef uint16_t Py_UCS2; typedef uint8_t Py_UCS1;
Hubungan yang sepadan adalah seperti berikut:
文本類型 | 字符存儲單元 | 字符存儲單元大小(字節(jié)) |
---|---|---|
PyUnicode_1BYTE_KIND | Py_UCS1 | 1 |
PyUnicode_2BYTE_KIND | Py_UCS2 | 2 |
PyUnicode_4BYTE_KIND | Py_UCS4 | 4 |
Sejak Unicode struktur storan dalaman berbeza-beza bergantung pada jenis teks, jenis jenis mesti disimpan sebagai medan awam objek Unicode. Python secara dalaman mentakrifkan beberapa bit bendera sebagai medan awam Unicode: (Disebabkan tahap pengarang yang terhad, semua medan di sini tidak akan diperkenalkan dalam kandungan seterusnya. Anda boleh mempelajarinya sendiri kemudian. Pegang penumbuk anda~)
-
dibawa masuk: Sama ada hendak mengekalkan mekanisme yang diinternet
jenis: jenis, digunakan untuk membezakan saiz unit storan asas bagi aksara
padat: kaedah peruntukan memori, sama ada objek dan penimbal teks dipisahkan
asscii: sama ada teks semuanya ASCII tulen
melalui fungsi PyUnicode_New, mengikut bilangan saiz aksara teks dan maxchar aksara maksimum memulakan objek Unicode. Fungsi ini terutamanya memilih unit storan aksara yang paling padat dan struktur asas untuk objek Unicode berdasarkan maxchar: (Kod sumber agak panjang, jadi ia tidak akan disenaraikan di sini. Anda boleh memahaminya sendiri. Ia ditunjukkan dalam bentuk jadual di bawah )
maxchar < 128 | 128 <= maxchar < 256 | 256 <= maxchar < 65536 | 65536 <= maxchar < MAX_UNICODE | |
---|---|---|---|---|
kind | PyUnicode_1BYTE_KIND | PyUnicode_1BYTE_KIND | PyUnicode_2BYTE_KIND | PyUnicode_4BYTE_KIND |
ascii | 1 | 0 | 0 | 0 |
字符存儲單元大?。ㄗ止?jié)) | 1 | 1 | 2 | 4 |
底層結(jié)構(gòu)體 | PyASCIIObject | PyCompactUnicodeObject | PyCompactUnicodeObject | PyCompactUnicodeObject |
3 Unicode對象的底層結(jié)構(gòu)體
3.1 PyASCIIObject
C源碼:
typedef struct { PyObject_HEAD Py_ssize_t length; /* Number of code points in the string */ Py_hash_t hash; /* Hash value; -1 if not set */ struct { unsigned int interned:2; unsigned int kind:3; unsigned int compact:1; unsigned int ascii:1; unsigned int ready:1; unsigned int :24; } state; wchar_t *wstr; /* wchar_t representation (null-terminated) */ } PyASCIIObject;
源碼分析:
length:文本長度
hash:文本哈希值
state:Unicode對象標(biāo)志位
wstr:緩存C字符串的一個wchar_t指針,以“\0”結(jié)束(這里和我看的另一篇文章講得不太一樣,另一個描述是:ASCII文本緊接著位于PyASCIIObject結(jié)構(gòu)體后面,我個人覺得現(xiàn)在的這種說法比較準確,畢竟源碼結(jié)構(gòu)體后面沒有別的字段了)
圖示如下:
(注意這里state字段后面有一個4字節(jié)大小的空洞,這是結(jié)構(gòu)體字段內(nèi)存對齊造成的現(xiàn)象,主要是為了優(yōu)化內(nèi)存訪問效率)
ASCII文本由wstr指向,以’abc’和空字符串對象’'為例:
3.2 PyCompactUnicodeObject
如果文本不全是ASCII,Unicode對象底層便由PyCompactUnicodeObject結(jié)構(gòu)體保存。C源碼如下:
/* Non-ASCII strings allocated through PyUnicode_New use the PyCompactUnicodeObject structure. state.compact is set, and the data immediately follow the structure. */ typedef struct { PyASCIIObject _base; Py_ssize_t utf8_length; /* Number of bytes in utf8, excluding the * terminating \0. */ char *utf8; /* UTF-8 representation (null-terminated) */ Py_ssize_t wstr_length; /* Number of code points in wstr, possible * surrogates count as two code points. */ } PyCompactUnicodeObject;
PyCompactUnicodeObject在PyASCIIObject的基礎(chǔ)上增加了3個字段:
utf8_length:文本UTF8編碼長度
utf8:文本UTF8編碼形式,緩存以避免重復(fù)編碼運算
wstr_length:wstr的“長度”(這里所謂的長度沒有找到很準確的說法,筆者也不太清楚怎么能打印出來,大家可以自行研究下)
注意到,PyASCIIObject中并沒有保存UTF8編碼形式,這是因為ASCII本身就是合法的UTF8,這也是ASCII文本底層由PyASCIIObject保存的原因。
結(jié)構(gòu)圖示:
3.3 PyUnicodeObject
PyUnicodeObject則是Python中str對象的具體實現(xiàn)。C源碼如下:
/* Strings allocated through PyUnicode_FromUnicode(NULL, len) use the PyUnicodeObject structure. The actual string data is initially in the wstr block, and copied into the data block using _PyUnicode_Ready. */ typedef struct { PyCompactUnicodeObject _base; union { void *any; Py_UCS1 *latin1; Py_UCS2 *ucs2; Py_UCS4 *ucs4; } data; /* Canonical, smallest-form Unicode buffer */ } PyUnicodeObject;
3.4 示例
在日常開發(fā)時,要結(jié)合實際情況注意字符串拼接前后的內(nèi)存大小差別:
>>> import sys >>> text = 'a' * 1000 >>> sys.getsizeof(text) 1049 >>> text += '????' >>> sys.getsizeof(text) 4080
4 interned機制
如果str對象的interned標(biāo)志位為1,Python虛擬機將為其開啟interned機制,
源碼如下:(相關(guān)信息在網(wǎng)上可以看到很多說法和解釋,這里筆者能力有限,暫時沒有找到最確切的答案,之后補充。抱拳~但是我們通過分析源碼應(yīng)該是能看出一些門道的)
/* This dictionary holds all interned unicode strings. Note that references to strings in this dictionary are *not* counted in the string's ob_refcnt. When the interned string reaches a refcnt of 0 the string deallocation function will delete the reference from this dictionary. Another way to look at this is that to say that the actual reference count of a string is: s->ob_refcnt + (s->state ? 2 : 0) */ static PyObject *interned = NULL; void PyUnicode_InternInPlace(PyObject **p) { PyObject *s = *p; PyObject *t; #ifdef Py_DEBUG assert(s != NULL); assert(_PyUnicode_CHECK(s)); #else if (s == NULL || !PyUnicode_Check(s)) return; #endif /* If it's a subclass, we don't really know what putting it in the interned dict might do. */ if (!PyUnicode_CheckExact(s)) return; if (PyUnicode_CHECK_INTERNED(s)) return; if (interned == NULL) { interned = PyDict_New(); if (interned == NULL) { PyErr_Clear(); /* Don't leave an exception */ return; } } Py_ALLOW_RECURSION t = PyDict_SetDefault(interned, s, s); Py_END_ALLOW_RECURSION if (t == NULL) { PyErr_Clear(); return; } if (t != s) { Py_INCREF(t); Py_SETREF(*p, t); return; } /* The two references in interned are not counted by refcnt. The deallocator will take care of this */ Py_REFCNT(s) -= 2; _PyUnicode_STATE(s).interned = SSTATE_INTERNED_MORTAL; }
可以看到,源碼前面還是做一些基本的檢查。我們可以看一下37行和50行:將s添加到interned字典中時,其實s同時是key和value(這里我不太清楚為什么會這樣做),所以s對應(yīng)的引用計數(shù)是+2了的(具體可以看PyDict_SetDefault()的源碼),所以在50行時會將計數(shù)-2,保證引用計數(shù)的正確。
考慮下面的場景:
>>> class User: def __init__(self, name, age): self.name = name self.age = age >>> user = User('Tom', 21) >>> user.__dict__ {'name': 'Tom', 'age': 21}
由于對象的屬性由dict保存,這意味著每個User對象都要保存一個str對象‘name’,這會浪費大量的內(nèi)存。而str是不可變對象,因此Python內(nèi)部將有潛在重復(fù)可能的字符串都做成單例模式,這就是interned機制。Python具體做法就是在內(nèi)部維護一個全局dict對象,所有開啟interned機制的str對象均保存在這里,后續(xù)需要使用的時候,先創(chuàng)建,如果判斷已經(jīng)維護了相同的字符串,就會將新創(chuàng)建的這個對象回收掉。
示例:
由不同運算生成’abc’,最后都是同一個對象:
>>> a = 'abc' >>> b = 'ab' + 'c' >>> id(a), id(b), a is b (2752416949872, 2752416949872, True)
Atas ialah kandungan terperinci Analisis kod sumber str jenis terbina dalam Python. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undress AI Tool
Gambar buka pakaian secara percuma

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Kunci untuk menangani pengesahan API adalah untuk memahami dan menggunakan kaedah pengesahan dengan betul. 1. Apikey adalah kaedah pengesahan yang paling mudah, biasanya diletakkan dalam tajuk permintaan atau parameter URL; 2. BasicAuth menggunakan nama pengguna dan kata laluan untuk penghantaran pengekodan Base64, yang sesuai untuk sistem dalaman; 3. OAuth2 perlu mendapatkan token terlebih dahulu melalui client_id dan client_secret, dan kemudian bawa bearertoken dalam header permintaan; 4. Untuk menangani tamat tempoh token, kelas pengurusan token boleh dikemas dan secara automatik menyegarkan token; Singkatnya, memilih kaedah yang sesuai mengikut dokumen dan menyimpan maklumat utama adalah kunci.

Untuk menguji API, anda perlu menggunakan Perpustakaan Permintaan Python. Langkah -langkahnya adalah untuk memasang perpustakaan, menghantar permintaan, mengesahkan respons, menetapkan masa dan cuba semula. Pertama, pasang perpustakaan melalui PipinstallRequests; kemudian gunakan permintaan.get () atau requests.post () dan kaedah lain untuk menghantar permintaan GET atau pos; Kemudian semak respons.status_code dan response.json () untuk memastikan hasil pulangan mematuhi jangkaan; Akhirnya, tambah parameter tamat masa untuk menetapkan masa tamat, dan menggabungkan perpustakaan semula untuk mencapai percubaan automatik untuk meningkatkan kestabilan.

Dalam Python, pembolehubah yang ditakrifkan di dalam fungsi adalah pembolehubah tempatan dan hanya sah dalam fungsi; Ditakrifkan secara luaran adalah pembolehubah global yang boleh dibaca di mana sahaja. 1. Pembolehubah tempatan dimusnahkan kerana fungsi dilaksanakan; 2. Fungsi ini boleh mengakses pembolehubah global tetapi tidak dapat diubahsuai secara langsung, jadi kata kunci global diperlukan; 3. Jika anda ingin mengubah suai pembolehubah fungsi luar dalam fungsi bersarang, anda perlu menggunakan kata kunci nonlocal; 4. Pembolehubah dengan nama yang sama tidak mempengaruhi satu sama lain dalam skop yang berbeza; 5. Global mesti diisytiharkan apabila mengubah suai pembolehubah global, jika tidak, kesilapan unboundlocalerror akan dibangkitkan. Memahami peraturan ini membantu mengelakkan pepijat dan menulis lebih banyak fungsi yang boleh dipercayai.

Untuk mewujudkan API moden dan cekap menggunakan Python, FastAPI disyorkan; Ia berdasarkan kepada jenis python standard yang diminta dan secara automatik dapat menghasilkan dokumen, dengan prestasi yang sangat baik. Selepas memasang FastAPI dan Asgi Server UVicorn, anda boleh menulis kod antara muka. Dengan menentukan laluan, menulis fungsi pemprosesan, dan data yang kembali, API boleh dibina dengan cepat. FastAPI menyokong pelbagai kaedah HTTP dan menyediakan sistem dokumentasi Swaggersui dan Redoc yang dihasilkan secara automatik. Parameter URL boleh ditangkap melalui definisi laluan, manakala parameter pertanyaan boleh dilaksanakan dengan menetapkan nilai lalai untuk parameter fungsi. Penggunaan rasional model Pydantic dapat membantu meningkatkan kecekapan dan ketepatan pembangunan.

Tambah kawalan tamat masa ke Python untuk gelung. 1. Anda boleh merakam masa mula dengan modul masa, dan menilai sama ada ia ditetapkan dalam setiap lelaran dan menggunakan rehat untuk melompat keluar dari gelung; 2. Untuk mengundi tugas kelas, anda boleh menggunakan gelung sementara untuk memadankan penghakiman masa, dan menambah tidur untuk mengelakkan kepenuhan CPU; 3. Kaedah lanjutan boleh mempertimbangkan threading atau isyarat untuk mencapai kawalan yang lebih tepat, tetapi kerumitannya tinggi, dan tidak disyorkan untuk pemula memilih; Ringkasan Mata Utama: Penghakiman masa manual adalah penyelesaian asas, sementara lebih sesuai untuk tugas kelas menunggu masa yang terhad, tidur sangat diperlukan, dan kaedah lanjutan sesuai untuk senario tertentu.

Bagaimana cara mengendalikan fail JSON yang besar di Python? 1. Gunakan Perpustakaan IJSON untuk mengalir dan mengelakkan limpahan memori melalui parsing item demi item; 2. Jika dalam format Jsonlines, anda boleh membacanya dengan garis dan memprosesnya dengan json.loads (); 3. Atau memecah fail besar ke dalam kepingan kecil dan kemudian memprosesnya secara berasingan. Kaedah ini dengan berkesan menyelesaikan masalah batasan memori dan sesuai untuk senario yang berbeza.

Di Python, kaedah melintasi tupel dengan gelung termasuk secara langsung melelehkan unsur -unsur, mendapatkan indeks dan elemen pada masa yang sama, dan memproses tuple bersarang. 1. Gunakan gelung untuk terus mengakses setiap elemen dalam urutan tanpa menguruskan indeks; 2. Gunakan penghitungan () untuk mendapatkan indeks dan nilai pada masa yang sama. Indeks lalai adalah 0, dan parameter permulaan juga boleh ditentukan; 3. Di samping itu, tuple tidak berubah dan kandungan tidak dapat diubah suai dalam gelung. Nilai yang tidak diingini boleh diabaikan oleh \ _. Adalah disyorkan untuk memeriksa sama ada tuple kosong sebelum melintasi untuk mengelakkan kesilapan.

Parameter lalai Python dinilai dan nilai tetap apabila fungsi ditakrifkan, yang boleh menyebabkan masalah yang tidak dijangka. Menggunakan objek berubah -ubah seperti senarai sebagai parameter lalai akan mengekalkan pengubahsuaian, dan disyorkan untuk menggunakan tiada sebaliknya; Skop parameter lalai adalah pembolehubah persekitaran apabila ditakrifkan, dan perubahan pembolehubah berikutnya tidak akan menjejaskan nilai mereka; Elakkan bergantung pada parameter lalai untuk menyelamatkan keadaan, dan keadaan enkapsulasi kelas harus digunakan untuk memastikan konsistensi fungsi.
