Python 문자열 대상 실현 원리 상세 설명
>>> import sys
>>> sys.getsizeof(1000)
28
>>> sys.getsizeof(2000)
28
>>> sys.getsizeof("python")
55
>>> sys.getsizeof("java")
53
위 와 같이 정수 대상 이 사용 하 는 메모 리 는 모두 28 바이트 로 구체 적 인 값 과 상 관 없 이 똑 같이 문자열 대상 입 니 다.서로 다른 문자열 대상 이 사용 하 는 메모리 가 다 릅 니 다.이것 이 바로 길 어 지 는 대상 입 니 다.길 어 지 는 대상 에 대해 대상 이 정의 할 때 대상 이 사용 하 는 메모리 공간 이 얼마 인지 모 릅 니 다.문자열 대상 은 Python 내부 에서 PyStringObject 로 PyStringObject 는 PyIntObject 와 마찬가지 로 가 변 대상 에 속 하 며 대상 이 생 성 되면 값 을 바 꿀 수 없습니다.(주의:길 어 지 는 대상 과 가 변 하지 않 는 대상 은 서로 다른 개념 입 니 다).Python StringObject 의 정의:
[stringobject.h]
typedef struct {
PyObject_VAR_HEAD
long ob_shash;
int ob_sstate;
char ob_sval[1];
} PyStringObject;
Python 의 문자열 대상 내 부 는 하나의 문자 배열 로 유지 되 고 있 음 을 알 수 있 습 니 다.정수 의 실현 원리 에 대해 서 는 PyObject 를 언급 합 니 다.HEAD,PyObject 에 대해VAR_HEAD 는 바로 PyObjectHEAD 에 ob 하나 더 추가크기 속성:
[object.h]
#define PyObject_VAR_HEAD
PyObject_HEAD
int ob_size; /* Number of items in variable part */
typedef struct {
PyObject_VAR_HEAD
} PyVarObject;
[stringobject.c]
PyObject * PyString_FromString(const char *str)
{
register size_t size;
register PyStringObject *op;
assert(str != NULL);
size = strlen(str);
// [1]
if (size > PY_SSIZE_T_MAX - PyStringObject_SIZE) {
PyErr_SetString(PyExc_OverflowError,
"string is too long for a Python string");
return NULL;
}
// [2]
if (size == 0 && (op = nullstring) != NULL) {
#ifdef COUNT_ALLOCS
null_strings++;
#endif
Py_INCREF(op);
return (PyObject *)op;
}
// [3]
if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL) {
#ifdef COUNT_ALLOCS
one_strings++;
#endif
Py_INCREF(op);
return (PyObject *)op;
}
// [4]
/* Inline PyObject_NewVar */
op = (PyStringObject *)PyObject_MALLOC(PyStringObject_SIZE + size);
if (op == NULL)
return PyErr_NoMemory();
PyObject_INIT_VAR(op, &PyString_Type, size);
op->ob_shash = -1;
op->ob_sstate = SSTATE_NOT_INTERNED;
Py_MEMCPY(op->ob_sval, str, size+1);
/* share short strings */
if (size == 0) {
PyObject *t = (PyObject *)op;
PyString_InternInPlace(&t);
op = (PyStringObject *)t;
nullstring = op;
Py_INCREF(op);
} else if (size == 1) {
PyObject *t = (PyObject *)op;
PyString_InternInPlace(&t);
op = (PyStringObject *)t;
characters[*str & UCHAR_MAX] = op;
Py_INCREF(op);
}
return (PyObject *) op;
}
PyStringObject 의 obsstate 속성 은 문자열 대상 이 intern 메커니즘 을 거 쳤 는 지,intern 처리 후의 문자열 을 표시 하 는 데 사 용 됩 니 다.예 를 들 어"Python"은 해석 기 가 실행 되 는 과정 에서 유일한 문자열 인"Python"에 대응 하 는 PyStringObject 대상 만 있 습 니 다.
>>> a = "python"
>>> b = "python"
>>> a is b
True
위 에서 보 듯 이 a 를 만 들 때 시스템 은 먼저 새로운 PyStringObject 대상 을 만 든 다음 에 intern 메커니즘 으로 처리 합 니 다(PyStringInterninPlace)이 어 intern 메커니즘 으로 처 리 된 PyStringObject 대상 을 찾 습 니 다.이 문자열 에 대응 하 는 PyStringObject 가 존재 하 는 것 을 발견 하면 이 대상 으로 돌아 갑 니 다.그렇지 않 으 면 방금 만 든 PyStringObject 를 intern 시스템 에 추가 합 니 다.a 와 b 문자열 의 액면가 가 같 기 때문에 a 와 b 는 같은 PyStringObject("python")대상 을 가리킨다.그렇다면 인터넷 내 부 는 또 어떤 메커니즘 일 까?
[stringobject.c]
static PyObject *interned;
void PyString_InternInPlace(PyObject **p)
{
register PyStringObject *s = (PyStringObject *)(*p);
PyObject *t;
if (s == NULL || !PyString_Check(s))
Py_FatalError("PyString_InternInPlace: strings only please!");
/* If it's a string subclass, we don't really know what putting
it in the interned dict might do. */
// [1]
if (!PyString_CheckExact(s))
return;
// [2]
if (PyString_CHECK_INTERNED(s))
return;
// [3]
if (interned == NULL) {
interned = PyDict_New();
if (interned == NULL) {
PyErr_Clear(); /* Don't leave an exception */
return;
}
}
t = PyDict_GetItem(interned, (PyObject *)s);
if (t) {
Py_INCREF(t);
Py_DECREF(*p);
*p = t;
return;
}
if (PyDict_SetItem(interned, (PyObject *)s, (PyObject *)s) < 0) {
PyErr_Clear();
return;
}
/* The two references in interned are not counted by refcnt.
The string deallocator will take care of this */
Py_REFCNT(s) -= 2;
PyString_CHECK_INTERNED(s) = SSTATE_INTERNED_MORTAL;
}
1.우선 형식 검사,intern 메커니즘 은 문자열 만 처리 합 니 다.2.이 PyStringObject 대상 이 이미 intern 메커니즘 처 리 를 한 적 이 있다 면 바로 되 돌려 줍 니 다.
3.interned 는 사실 사전 대상 입 니 다.null 일 때 사전 대상 을 초기 화 합 니 다.그렇지 않 으 면 이 사전 에 key(PyObject*)s 의 value 가 존재 하 는 지 확인 합 니 다.존재 한다 면 이 대상 의 인용 수 를 1 로 추가 하고 임시로 만 든 대상 의 인용 수 를 1 로 줄 입 니 다.그렇지 않 으 면(PyObject*)s 를 key 와 value 로 interned 사전 에 추가 하 는 동시에 인용 수 를 2 로 줄 입 니 다.이 두 인용 수 를 2 로 줄 인 것 은 interned 사전 에 의 해 인용 되 었 기 때 문 입 니 다.그러나 이 두 인용 은 쓰레기 회수 의 판단 근거 가 되 지 않 습 니 다.그렇지 않 으 면 문자열 대상 은 쓰레기 회수 기 에 의 해 영원히 수집 되 지 않 습 니 다.
상기 코드 에서 b 에 게"python"값 을 부여 한 후 시스템 에 PyStringObject 대상 을 몇 개 만 들 었 습 니까?정 답 은:2.b 를 만 들 때 임시 PyStringObject 가 사전 키 로 서 intened 에서 PyStringObject 대상 의 값 이"python"인지 찾 습 니 다.
문자열 버퍼
문자열 은 intern 메커니즘 캐 시 문자열 외 에 도 짧 은 문자열 버퍼 풀 characters 가 있 습 니 다.캐 시 문자열 길이 가 1 인 PyStringObject 대상 입 니 다.
static PyStringObject *characters[UCHAR_MAX + 1]; //UCHAR_MAX = 255
길이 가 1 인 문자열 을 만 들 때 흐름:
...
else if (size == 1) {
PyObject *t = (PyObject *)op;
PyString_InternInPlace(&t);
op = (PyStringObject *)t;
characters[*str & UCHAR_MAX] = op;
Py_INCREF(op);
요약:
1.문자열 은 PyStringObject 로 표시
2.문자열 은 길 어 지 는 대상 에 속 합 니 다.
3.문자열 은 가 변 대상 에 속 합 니 다.
4.문자열 은 intern 메커니즘 으로 python 의 효율 을 높 인 다.
5.문자열 은 버퍼 저장 길이 가 1 인 문자열 대상 이 있 습 니 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
로마 숫자를 정수로 또는 그 반대로 변환그 중 하나는 로마 숫자를 정수로 변환하는 함수를 만드는 것이었고 두 번째는 그 반대를 수행하는 함수를 만드는 것이었습니다. 문자만 포함합니다'I', 'V', 'X', 'L', 'C', 'D', 'M' ; 문자열이 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.