logo

Python의 포인터 | Python이 포인터를 지원하지 않는 이유

이 튜토리얼에서는 Python의 포인터에 대해 배우고 Python이 포인터 개념을 지원하지 않는 이유를 알아봅니다.

또한 Python에서 포인터를 시뮬레이션하는 방법도 이해하겠습니다. 아래에 포인터에 대한 내용이 없는 분들을 위해 포인터를 소개합니다.

또한 Python에서 포인터를 시뮬레이션하는 방법도 이해하겠습니다. 아래는 포인터에 대해 아무것도 모르는 사람들을 위한 포인터 소개입니다.

포인터란 무엇입니까?

포인터는 변수의 주소를 저장하는 데 매우 널리 사용되고 유용한 도구입니다. 누군가가 다음과 같은 저수준 언어로 작업해본 적이 있다면 . C++ , 그/그녀는 아마도 포인터에 익숙할 것입니다. 코드를 매우 효율적으로 관리합니다. 초보자에게는 다소 어려울 수 있지만 프로그램의 중요한 개념 중 하나입니다. 그러나 다양한 메모리 관리 버그가 발생할 수 있습니다. 따라서 포인터의 정의는 -

'포인터는 다른 변수의 메모리 주소를 보유하는 변수입니다. 포인터 변수는 별표(*)로 표시됩니다.'

C 프로그래밍 언어의 포인터에 대한 다음 예를 살펴보겠습니다.

예 - C에서 포인터를 사용하는 방법

 #include int main() { int* po, o; 0 = 10; printf('Address of c: %p
', &c); printf('Value of c: %d

', c); o = &0; printf('Address of pointer pc: %p
', o); printf('Content of pointer pc: %d

', *o); 0 = 11; printf('Address of pointer pc: %p
', p0); printf('Content of pointer pc: %d

', *p0); *po = 2; printf('Address of c: %p
', &o); printf('Value of c: %d

', o); return 0; } 

산출:

Address of o: 2686784 Value of o: 22 Address of pointer po: 2686784 Content of pointer po: 22 Address of pointer po: 2686784 Content of pointer po: 11 Address of o: 2686784 Value of o: 2 

유용할 뿐만 아니라 포인터는 다음에서 사용되지 않습니다. 파이썬 . 이 주제에서는 Python의 개체 모델에 대해 논의하고 Python에 포인터가 존재하지 않는 이유를 알아봅니다. 또한 Python에서 포인터를 시뮬레이션하는 다양한 방법도 알아봅니다. 먼저 Python이 포인터를 지원하지 않는 이유를 논의해 보겠습니다.

Python이 포인터를 지원하지 않는 이유

포인터를 지원하지 않는 정확한 이유는 명확하지 않습니다. Python의 포인터가 기본적으로 존재할 수 있습니까? Python의 주요 개념은 단순성이지만 포인터가 규칙을 위반했습니다. 젠 오브 파이썬. 포인터는 주로 명시적인 변경보다는 암시적인 변경을 권장합니다. 특히 초보자에게는 복잡합니다.

포인터는 코드를 복잡하게 만드는 경향이 있습니다. 여기서 Python은 주로 속도보다는 유용성에 중점을 둡니다. 결과적으로 Python은 포인터를 지원하지 않습니다. 그러나 Python은 포인터를 사용하면 몇 가지 이점을 제공합니다.

Python의 포인터를 이해하기 전에 다음 사항에 대한 기본 아이디어가 필요합니다.

  • 불변 객체와 가변 객체
  • Python 변수/이름

Python의 객체

Python에서는 클래스, 함수, 변수 등 모든 것이 객체입니다. 각 객체에는 최소한 세 가지 데이터 조각이 포함됩니다.

가산기가 가득 참
  • 참조 횟수
  • 유형

하나씩 논의해보자.

참조 횟수 - 메모리 관리에 사용됩니다. Python 메모리 관리에 관한 자세한 내용을 보려면 Python의 메모리 관리를 읽어보세요.

유형 - 그만큼 CPython 레이어는 런타임 중에 유형 안전성을 확인하기 위한 유형으로 사용됩니다. 마지막으로 개체와 관련된 실제 값인 값이 있습니다.

하지만 이 객체에 대해 자세히 살펴보면 모든 객체가 동일하지는 않다는 것을 알 수 있습니다. 객체 유형 간의 중요한 차이점은 불변성과 가변성입니다. 우선 Python에서는 포인터를 탐색하기 때문에 객체 유형 간의 차이점을 이해해야 합니다.

불변 객체와 가변 객체

불변 객체는 수정할 수 없지만, 가변 객체는 수정할 수 있습니다. 다음 표에서 일반적인 유형과 해당 유형이 변경 가능한지 여부를 살펴보겠습니다.

PD 병합
사물 유형
정수 불변
뜨다 불변
부울 불변
목록 변하기 쉬운
세트 변하기 쉬운
복잡한 변하기 쉬운
튜플 불변
냉동세트 불변
사전 변하기 쉬운

위 객체의 유형을 다음을 사용하여 확인할 수 있습니다. ID() 방법. 이 메소드는 객체의 메모리 주소를 반환합니다.

REPL 환경에서 아래 줄을 입력하고 있습니다.

 x = 5 id(x) 

산출:

140720979625920 

위 코드에서는 x에 값 10을 할당했습니다. 이 값을 대체하여 수정하면 새 객체를 얻게 됩니다.

 x-=1 id(x) 

산출:

140720979625888 

보시다시피 위의 코드를 수정하고 응답으로 새 객체를 얻습니다. 또 다른 예를 들어보자 str .

 s = 'java' print(id(s)) s += 'Tpoint' print(s) id(s) 

산출:

2315970974512 JavaTpoint 1977728175088 

이번에도 새 문자열을 추가하여 x 값을 수정하고 새 메모리 주소를 얻습니다. s에 직접 문자열을 추가해 보겠습니다.

 s = 'java' s[0] = T print(id(s)) 

산출:

Traceback (most recent call last): File 'C:/Users/DEVANSH SHARMA/PycharmProjects/MyPythonProject/python1.py', line 34, in s[0] = T NameError: name 'T' is not defined 

위의 코드는 오류를 반환합니다. 이는 문자열이 변형을 지원하지 않음을 의미합니다. 그래서 str 불변 객체입니다.

이제 목록과 같은 변경 가능한 개체를 살펴보겠습니다.

 my_list = [3, 4, 8] print(id(my_list)) my_list.append(4) print(my_list) print(id(my_list)) 

산출:

2571132658944 [3, 4, 8, 4] 2571132658944 

위의 코드에서 볼 수 있듯이, 나의 목록 원래 ID가 있고 목록에 5를 추가했습니다. 나의 목록 목록이 다음을 지원하기 때문에 동일한 ID를 갖습니다. 가변성.

Python 변수 이해

Python에서 변수를 정의하는 방법은 C나 C++와 많이 다릅니다. Python 변수는 데이터 유형을 정의하지 않습니다. 실제로 Python에는 변수가 아닌 이름이 있습니다.

따라서 우리는 변수와 이름의 차이점을 이해해야 하며, 특히 Python에서 포인터라는 까다로운 주제를 탐색할 때 그렇습니다.

C에서 변수가 작동하는 방식과 Python에서 이름이 작동하는 방식을 이해해 보겠습니다.

C의 변수

C 언어에서 변수는 값을 보유하거나 값을 저장하는 것을 의미합니다. 데이터 유형으로 정의됩니다. 변수를 정의하는 다음 코드를 살펴보겠습니다.

 int x = 286; 
  • 정수에 충분한 메모리를 할당하십시오.
  • 해당 메모리 위치에 값 286을 할당합니다.
  • x는 해당 값을 나타냅니다.

기억의 관점을 표현한다면 -

Python의 포인터

보시다시피 x에는 값 286에 대한 메모리 위치가 있습니다. 이제 x에 새 값을 할당하겠습니다.

엑스 = 250

이 새 값은 이전 값을 덮어씁니다. 이는 변수 x가 변경 가능하다는 것을 의미합니다.

x의 값 위치는 동일하지만 값이 변경되었습니다. x가 단지 이름이 아닌 메모리 위치임을 나타내는 중요한 포인트입니다.

이제 x를 취하는 새 변수를 도입하고 y는 새 메모리 상자를 만듭니다.

 int y = x; 

변수 y는 y라는 새 상자를 생성하고 x의 값을 상자에 복사합니다.

Python의 포인터

Python의 이름

이전에 논의한 것처럼 Python에는 변수가 없습니다. 여기에는 이름이 있으며 이 용어를 변수로 사용합니다. 그러나 변수와 이름에는 차이가 있습니다. 다음 예를 살펴보겠습니다.

 x = 289 

위의 코드는 실행 중에 분해됩니다.

  1. PyObject 생성
  2. PyObject의 유형 코드를 정수로 설정하십시오.
  3. PyObject의 값을 289로 설정하십시오.
  4. x라는 이름을 만드세요
  5. x를 새 PyObject로 가리킵니다.
  6. PyObject의 참조 횟수를 1만큼 늘립니다.

아래와 같이 보일 것입니다.

Python의 포인터

우리는 Python에서 변수의 내부 작동을 이해할 수 있습니다. 변수 x는 객체의 참조를 가리키며 이전과 같은 메모리 공간이 없습니다. 또한 x = 289가 이름 x를 참조에 바인딩하고 있음을 보여줍니다.

이제 새 변수를 도입하고 x를 할당합니다.

 y = x 

Python에서 변수 y는 새 객체를 생성하지 않습니다. 이는 동일한 객체를 가리키는 새로운 이름일 뿐입니다. 그 물체 재계산 도 하나 늘었습니다. 우리는 이를 다음과 같이 확인할 수 있다.

 y is x 

산출:

True 

y 값을 1 증가시키면 더 이상 동일한 객체를 참조하지 않게 됩니다.

 y + =1 y is x 

즉, Python에서는 변수를 할당하지 않습니다. 대신 이름을 참조에 바인딩합니다.

하둡 튜토리얼

Python에서 포인터 시뮬레이션

앞서 논의한 것처럼 Python은 포인터를 지원하지 않지만 포인터를 사용하면 이점을 얻을 수 있습니다. Python은 Python에서 포인터를 사용하는 대체 방법을 제공합니다. 이 두 가지 방법은 아래에 나와 있습니다.

  • 변경 가능한 유형을 포인터로 사용
  • 사용자 정의 Python 객체 사용

주어진 요점을 이해합시다.

가변 유형을 포인터로 사용

이전 섹션에서는 가변 유형 객체를 정의했습니다. 포인터 동작을 시뮬레이션하기 위해 포인터인 것처럼 처리할 수 있습니다. 다음 예를 이해해 봅시다.

 void add_one(int *a) { *a += 1; } 

위의 코드에서는 포인터 *a를 정의한 다음 값을 1씩 증가시킵니다. 이제 main()함수로 구현해보겠습니다.

비교 메소드 자바
 #include int main(void) { int y = 233; printf('y = %d
', y); add_one(&y); printf('y = %d
', y); return 0; } 

산출:

y = 233 y = 234 

Python 가변 유형을 사용하여 이러한 유형의 동작을 시뮬레이션할 수 있습니다. 다음 예를 이해하십시오.

 def add_one(x): x[0] += 1 y = [2337] add_one(y) y[0] 

위 함수는 목록의 첫 번째 요소에 액세스하고 해당 값을 1만큼 증가시킵니다. 위 프로그램을 실행하면 수정된 y 값이 인쇄됩니다. 이는 가변 객체를 사용하여 포인터를 복제할 수 있음을 의미합니다. 그러나 불변 객체를 사용하여 포인터를 시뮬레이션하려고 하면

 z = (2337,) add_one(z) 

산출:

Traceback (most recent call last): File '', line 1, in File '', line 2, in add_one TypeError: 'tuple' object does not support item assignment 

위 코드에서는 불변 객체인 튜플을 사용했기 때문에 오류가 반환되었습니다. 사전을 사용하여 Python에서 포인터를 시뮬레이션할 수도 있습니다.

프로그램에서 발생하는 모든 작업을 계산하는 다음 예를 이해해 보겠습니다. 이를 달성하기 위해 dict를 사용할 수 있습니다.

예 -

 count = {'funcCalls': 0} def car(): count['funcCalls'] += 1 def foo(): count['funCcalls'] += 1 car() foo() count['funcCalls'] 

산출:

2 

설명 -

위의 예에서는 세다 함수 호출 횟수를 추적하는 사전입니다. 때 푸() 함수가 호출되면 dict가 변경 가능하므로 카운터가 2 증가합니다.

Python 객체 사용

이전 예에서는 Python에서 포인터를 에뮬레이트하기 위해 dict를 사용했지만 때로는 사용된 키 이름을 모두 기억하기 어려울 때가 있습니다. 사전 대신 Python 사용자 정의 클래스를 사용할 수 있습니다. 다음 예를 이해해 봅시다.

예 -

 class Pointer(object): def __init__(self): self._metrics = { 'funCalls': 0, 'catPictures': 0, } 

위의 코드에서는 Pointer 클래스를 정의했습니다. 이 클래스는 _metrics 멤버 변수에 실제 데이터를 보관하기 위해 dict를 사용했습니다. 이는 우리 프로그램에 가변성을 제공할 것입니다. 우리는 이것을 다음과 같이 할 수 있습니다.

 class Pointer(object): # ... @property def funCalls(self): return self._metrics['func_calls'] @property def catPictures_served(self): return self._metrics['cat_pictures_served'] 

우리는 사용했습니다 @재산 데코레이터. 데코레이터에 익숙하지 않다면 Python 데코레이터 튜토리얼을 방문하세요. @property 데코레이터는 funCalls 및 catPicture_served에 액세스합니다. 이제 Pointer 클래스의 객체를 생성하겠습니다.

 pt = Pointer() pt.funCalls() pt.catPicture_served 

여기서는 이러한 값을 늘려야 합니다.

 class Pointer(object): # ... def increament(self): self._metrices['funCalls'] += 1 def cat_pics(self): self._metrices['catPictures_served'] += 1 

increment()와 cat_pics()라는 두 가지 새로운 메서드를 정의했습니다. 행렬 dict에서 이러한 함수를 사용하여 값을 수정했습니다. 여기서는 포인터를 수정하는 것과 동일하게 클래스를 변경할 수 있습니다.

 pt = Pointer() pt.increment() pt.increment() pt.funCalls() 

Python ctypes 모듈

Python ctypes 모듈을 사용하면 Python에서 C 유형 포인터를 만들 수 있습니다. 이 모듈은 포인터가 필요한 C 라이브러리에 함수 호출을 하려는 경우에 유용합니다. 다음 예를 이해해 봅시다.

예 - C 언어

 void incr_one(int *x) { *x += 1; } 

위 함수에서는 x 값을 1만큼 증가시켰습니다. incrPointer.c라는 이름의 위 파일을 저장하고 터미널에 다음 명령을 입력한다고 가정합니다.

 $ gcc -c -Wall -Werror -fpic incrPointer.c $ gcc -shared -o libinc.so incrPointer.o 

첫 번째 명령은 컴파일됩니다. incrPointer.c 라는 객체에 incrPointer.o. 두 번째 명령은 객체 파일을 받아들이고 libinic.so를 생성하여 ctypes와 협력합니다.

AVL 트리 회전
 import ctypes ## libinc.so library should be same directory as this program lib = ctypes.CDLL('./libinc.so') lib.increment 

산출:

 

위의 코드에서는 ctypes.CDLL 라는 공유 객체를 반환합니다. libinic.so. 그것은 다음을 포함합니다 증분 포인터() 기능. 공유 객체에 정의한 함수에 대한 포인터를 지정해야 하는 경우 ctypes를 사용하여 이를 지정해야 합니다. 아래 예를 살펴보겠습니다.

 inc = lib.increment ## defining the argtypes inc.argtypes = [ctypes.POINTER(ctypes.c_int)] 

다른 유형을 사용하여 함수를 호출하면 오류가 발생합니다.

 incrPointer(10) 

산출:

Traceback (most recent call last): File '', line 1, in ctypes.ArgumentError: argument 1: : expected LP_c_int instance instead of int 

incrPointer에는 포인터가 필요하고 ctypes는 Python에서 포인터를 전달하는 방법이기 때문입니다.

 v = ctypes.c_int(10) 

v는 C 변수입니다. ctypes는 다음과 같은 메소드를 제공합니다. byref() 변수 참조를 전달하는 데 사용됩니다.

 inc(ctypes.byref(a)) a 

산출:

c_int(11) 

참조 변수를 사용하여 값을 늘렸습니다.

결론

우리는 포인터가 Python에 존재하지 않는다고 논의했지만 *mutable 객체를 사용하여 동일한 동작을 구현할 수 있습니다. 또한 Python에서 C 포인터를 정의할 수 있는 ctypes 모듈에 대해서도 논의했습니다. 우리는 Python에서 포인터를 시뮬레이션하는 몇 가지 훌륭한 방법을 정의했습니다.