python - لغة - مكتبة اكواد بايثون
لماذا يتغير حجم سلسلة Python هذه عند تحويل int فاشل (1)
من سقسقة هنا :
import sys
x = 'ñ'
print(sys.getsizeof(x))
int(x) #throws an error
print(sys.getsizeof(x))
نحصل على 74 ، ثم 77 بايت للمكالمات
getsizeof
اثنين.
يبدو أننا نقوم بإضافة 3 بايت إلى الكائن ، من استدعاء int الفاشلة.
بعض الأمثلة الأخرى من twitter (قد تحتاج إلى إعادة تشغيل python لإعادة ضبط الحجم إلى 74):
x = 'ñ'
y = 'ñ'
int(x)
print(sys.getsizeof(y))
77!
print(sys.getsizeof('ñ'))
int('ñ')
print(sys.getsizeof('ñ'))
74 ، ثم 77.
تطلب التعليمة البرمجية التي تحول السلاسل إلى ints في CPython 3.6 شكل UTF-8 من السلسلة للعمل مع :
buffer = PyUnicode_AsUTF8AndSize(asciidig, &buflen);
تقوم السلسلة بإنشاء تمثيل UTF-8 في المرة الأولى التي يتم فيها طلبها وتخزينها مؤقتًا على كائن السلسلة :
if (PyUnicode_UTF8(unicode) == NULL) {
assert(!PyUnicode_IS_COMPACT_ASCII(unicode));
bytes = _PyUnicode_AsUTF8String(unicode, NULL);
if (bytes == NULL)
return NULL;
_PyUnicode_UTF8(unicode) = PyObject_MALLOC(PyBytes_GET_SIZE(bytes) + 1);
if (_PyUnicode_UTF8(unicode) == NULL) {
PyErr_NoMemory();
Py_DECREF(bytes);
return NULL;
}
_PyUnicode_UTF8_LENGTH(unicode) = PyBytes_GET_SIZE(bytes);
memcpy(_PyUnicode_UTF8(unicode),
PyBytes_AS_STRING(bytes),
_PyUnicode_UTF8_LENGTH(unicode) + 1);
Py_DECREF(bytes);
}
البايتات الثلاثة الإضافية هي لتمثيل UTF-8.
قد تتساءل لماذا لا يتغير الحجم عندما تكون السلسلة مثل
'40'
أو
'plain ascii text'
.
هذا لأنه إذا كانت السلسلة في
تمثيل "ascii المضغوط"
، فإن Python لا تنشئ تمثيلًا UTF-8 منفصل.
تقوم
بإرجاع تمثيل ASCII مباشرةً
، وهو صالح بالفعل UTF-8:
#define PyUnicode_UTF8(op) \
(assert(_PyUnicode_CHECK(op)), \
assert(PyUnicode_IS_READY(op)), \
PyUnicode_IS_COMPACT_ASCII(op) ? \
((char*)((PyASCIIObject*)(op) + 1)) : \
_PyUnicode_UTF8(op))
قد تتساءل أيضًا لماذا لا يتغير الحجم لشيء مثل
'1'
.
هذا هو U + FF11 FULLWIDTH DIGIT ONE ، والذي يعامل
int
بما يعادل
'1'
.
ذلك لأن
واحدة من الخطوات السابقة
في عملية السلسلة إلى int هي
asciidig = _PyUnicode_TransformDecimalAndSpaceToASCII(u);
الذي يحول جميع أحرف المسافة البيضاء إلى
' '
ويحول كل الأرقام العشرية في Unicode إلى أرقام ASCII المقابلة.
يُرجع هذا التحويل السلسلة الأصلية إذا لم ينتهي تغيير أي شيء ، ولكن عندما يحدث تغييرات ، فإنه ينشئ سلسلة جديدة ، والسلسلة الجديدة هي السلسلة التي يتم فيها إنشاء تمثيل UTF-8.
بالنسبة للحالات التي يبدو فيها الاتصال
int
على سلسلة ما يؤثر على أخرى ، فهذه هي في الواقع نفس كائن السلسلة.
هناك العديد من الشروط التي بموجبها ستقوم Python بإعادة استخدام السلاسل ، كل هذا بنفس القدر من الحزم في Weird Implementation Detail Land مثل كل شيء ناقشناه حتى الآن.
بالنسبة
'ñ'
، يحدث إعادة الاستخدام لأن هذا عبارة عن سلسلة أحرف واحدة في نطاق Latin-1 (
'\x00'
-
'\xff'
) ، ويقوم التطبيق
بتخزينها وإعادة
'\xff'
.