programing

Python에서 포인터 시뮬레이션

yoursource 2021. 1. 17. 12:24
반응형

Python에서 포인터 시뮬레이션


사내 언어 (ihl)를 Python으로 크로스 컴파일하려고합니다.

ihl 기능 중 하나는 C 또는 C ++에서 기대하는 것처럼 동작하는 포인터와 참조입니다.

예를 들어 다음과 같이 할 수 있습니다.

a = [1,2];  // a has an array 
b = &a;     // b points to a
*b = 2;     // derefernce b to store 2 in a
print(a);   // outputs 2
print(*b);   // outputs 2

이 기능을 Python에서 복제하는 방법이 있습니까?

나는 내가 몇몇 사람들을 혼란스럽게 만들었다는 것을 지적해야한다. 파이썬에서 포인터를 원하지 않습니다. 저는 파이썬 전문가로부터 이해를 얻고 싶었습니다. 위에서 보여 드린 사례를 시뮬레이션하기 위해 생성해야하는 Python

내 파이썬은 최고는 아니지만 지금까지 내 탐험은 유망한 것을 산출하지 못했습니다. (

누군가가 더 적합한 다른 언어를 제안 할 수 있다면 우리는 실제로 Python에 묶여 있지 않도록 ihl에서 더 일반적인 언어로 이동하려고한다는 점을 지적해야합니다.


이것은 명시 적으로 수행 할 수 있습니다.

class ref:
    def __init__(self, obj): self.obj = obj
    def get(self):    return self.obj
    def set(self, obj):      self.obj = obj

a = ref([1, 2])
b = a
print a.get()  # => [1, 2]
print b.get()  # => [1, 2]

b.set(2)
print a.get()  # => 2
print b.get()  # => 2

C ++ 관점에서 Python 변수 이름의 의미론 을 읽을 수 있습니다 . 결론 : 모든 변수는 참조 입니다.

더 많은 지점으로, 변수의 관점에서 생각하지만, 할 수있는 개체의 측면에서하지 않는 이름 .


C와 유사한 언어를 컴파일하는 경우 다음과 같이 말하십시오.

func()
{
    var a = 1;
    var *b = &a;
    *b = 2;
    assert(a == 2);
}

파이썬으로 들어가면 모든 "파이썬의 모든 것이 참조입니다"라는 말은 잘못된 이름입니다.

파이썬의 모든 것이 참조라는 것은 사실이지만, 많은 핵심 유형 (ints, strings)이 불변이라는 사실은 많은 경우에 이것을 효과적으로 취소합니다. 파이썬에서 위를 구현하는 직접적인 방법 은 없습니다 .

이제 간접적으로 할 수 있습니다. 변경 불가능한 유형의 경우 변경 가능한 유형으로 래핑하십시오. Ephemient의 솔루션은 작동하지만 종종 이렇게합니다.

a = [1]
b = a
b[0] = 2
assert a[0] == 2

(2.xa에서 Python의 "nonlocal"부족을 해결하기 위해이 작업을 몇 번 수행했습니다.)

이것은 훨씬 더 많은 오버 헤드를 의미합니다. 모든 불변 유형 (또는 구별을 시도하지 않는 경우 모든 유형)은 갑자기 목록 (또는 다른 컨테이너 객체)을 생성하므로 변수에 대한 오버 헤드가 크게 증가합니다. 개별적으로는 많지는 않지만 전체 코드베이스에 적용될 때 합산됩니다.

불변 유형을 래핑하여이 값을 줄일 수 있지만 출력에서 ​​래핑 된 변수와 래핑되지 않은 변수를 추적해야하므로 "a"또는 "a [0]"을 사용하여 값에 액세스 할 수 있습니다. 적절하게. 아마 털이 될 것입니다.

이것이 좋은 생각인지 아닌지에 관해서는 당신이 그것을하는 이유에 달려 있습니다. VM을 실행하기 위해 무언가를 원하면 아니오라고 말하는 경향이 있습니다. Python에서 기존 언어를 호출 할 수 있도록하려면 기존 VM을 가져 와서 Python 바인딩을 만들어 Python에서 액세스하고 호출 할 수 있도록하는 것이 좋습니다.


내가 투표 한 ephemient answer 와 거의 똑같이 Python의 내장 속성 함수를 사용할 수 있습니다 . 인스턴스 에 액세스 ref하기 위해 사용 get하고 set메서드를 사용하는 대신 클래스 정의에서 속성 으로 ref할당 한 인스턴스의 속성을 호출하는 것을 제외하고는 ephemient의 대답에서 클래스 와 거의 비슷한 을 할 것 입니다. Python 문서에서 ( Cptr로 변경 한 경우 제외 ) :

class ptr(object):
    def __init__(self):
        self._x = None
    def getx(self):
        return self._x
    def setx(self, value):
        self._x = value
    def delx(self):
        del self._x
    x = property(getx, setx, delx, "I'm the 'x' property.")

두 방법 모두에 의존하지 않고 C 포인터처럼 작동합니다 global. 예를 들어 포인터를받는 함수가있는 경우 :

def do_stuff_with_pointer(pointer, property, value):
    setattr(pointer, property, value)

예를 들면

a_ref = ptr()      # make pointer
a_ref.x = [1, 2]   # a_ref pointer has an array [1, 2]
b_ref = a_ref      # b_ref points to a_ref
# pass ``ptr`` instance to function that changes its content
do_stuff_with_pointer(b_ref, 'x', 3)
print a_ref.x      # outputs 3
print b_ref.x      # outputs 3

또 다른 완전히 미친 옵션은 Python의 ctypes 를 사용하는 것 입니다. 이 시도:

from ctypes import *
a = py_object([1,2]) # a has an array 
b = a                # b points to a
b.value = 2          # derefernce b to store 2 in a
print a.value        # outputs 2
print b.value        # outputs 2

또는 정말 화려하고 싶다면

from ctypes import *
a = py_object([1,2])   # a has an array 
b = pointer(a)         # b points to a
b.contents.value = 2   # derefernce b to store 2 in a
print a.value          # outputs 2
print b.contents.value # outputs 2

OP의 원래 요청과 더 비슷합니다. 미친!


파이썬의 모든 것은 이미 포인터이지만 파이썬에서는 "참조"라고 불립니다. 다음은 코드를 Python으로 번역 한 것입니다.

a = [1,2]  // a has an array 
b = a     // b points to a
a = 2      // store 2 in a.
print(a)   // outputs 2
print(b)  // outputs [1,2]

"Dereferencing"은 모든 참조 이므로 의미가 없습니다 . 다른 것이 없으므로 역 참조 할 것이 없습니다.


다른 사람들이 말했듯이 모든 파이썬 변수는 본질적으로 포인터입니다.

C 관점에서 이것을 이해하는 열쇠는 unknown by many id () 함수를 사용하는 것입니다. 변수가 가리키는 주소를 알려줍니다.

>>> a = [1,2]
>>> id(a)
28354600

>>> b = a
>>> id(a)
28354600

>>> id(b)
28354600

이건 멍청하지만 생각이 ...

# Change operations like:
b = &a

# To:
b = "a"

# And change operations like:
*b = 2

# To:
locals()[b] = 2


>>> a = [1,2]
>>> b = "a"
>>> locals()[b] = 2
>>> print(a)
2
>>> print(locals()[b])
2

그러나 포인터 산술 등이 없으며 어떤 다른 문제에 부딪 힐 수 있는지 알려주지 않습니다.


class Pointer(object):
    def __init__(self, target=None):
        self.target = target

    _noarg = object()

    def __call__(self, target=_noarg):
        if target is not self._noarg:
            self.target = target
        return self.target
a = Pointer([1, 2])
b = a

print a() # => [1, 2]
print b() # => [1, 2]

b(2)
print a()  # => 2
print b()  # => 2

이 예는 짧고 명확하다고 생각합니다.

여기에 암시 적 목록이있는 클래스가 있습니다.

class A: 
   foo = []
a, b = A(), A()
a.foo.append(5)
b.foo
ans: [5]

이 메모리 프로필을 보면 (사용 from memory_profiler import profile:), 내 직감은 이것이 C에서와 같은 포인터를 어떻게 든 시뮬레이션 할 수 있음을 알려줍니다.

Filename: F:/MegaSync/Desktop/python_simulate_pointer_with_class.py

Line #    Mem usage    Increment   Line Contents
================================================
     7     31.2 MiB      0.0 MiB   @profile
     8                             def f():
     9     31.2 MiB      0.0 MiB       a, b = A(), A()
    10                                 #here memoery increase and is coupled
    11     50.3 MiB     19.1 MiB       a.foo.append(np.arange(5000000))
    12     73.2 MiB     22.9 MiB       b.foo.append(np.arange(6000000))
    13     73.2 MiB      0.0 MiB       return a,b


[array([      0,       1,       2, ..., 4999997, 4999998, 4999999]), array([      0,       1,       2, ..., 5999997, 5999998, 5999999])] [array([      0,       1,       2, ..., 4999997, 4999998, 4999999]), array([      0,       1,       2, ..., 5999997, 5999998, 5999999])]
Filename: F:/MegaSync/Desktop/python_simulate_pointer_with_class.py

Line #    Mem usage    Increment   Line Contents
================================================
    14     73.4 MiB      0.0 MiB   @profile
    15                             def g():
    16                                 #clearing b.foo list clears a.foo
    17     31.5 MiB    -42.0 MiB       b.foo.clear()
    18     31.5 MiB      0.0 MiB       return a,b


[] []
Filename: F:/MegaSync/Desktop/python_simulate_pointer_with_class.py

Line #    Mem usage    Increment   Line Contents
================================================
    19     31.5 MiB      0.0 MiB   @profile
    20                             def h():
    21                                 #and here mem. coupling is lost ;/
    22     69.6 MiB     38.1 MiB       b.foo=np.arange(10000000)
    23                                 #memory inc. when b.foo is replaced
    24    107.8 MiB     38.1 MiB       a.foo.append(np.arange(10000000))
    25                                 #so its seams that modyfing items of
    26                                 #existing object of variable a.foo,
    27                                 #changes automaticcly items of b.foo
    28                                 #and vice versa,but changing object
    29                                 #a.foo itself splits with b.foo
    30    107.8 MiB      0.0 MiB       return b,a


[array([      0,       1,       2, ..., 9999997, 9999998, 9999999])] [      0       1       2 ..., 9999997 9999998 9999999]

그리고 여기에 우리는 클래스에 명시적인 self가 있습니다.

class A: 
    def __init__(self): 
        self.foo = []
a, b = A(), A()
a.foo.append(5)
b.foo
ans: []

Filename: F:/MegaSync/Desktop/python_simulate_pointer_with_class.py

Line #    Mem usage    Increment   Line Contents
================================================
    44    107.8 MiB      0.0 MiB   @profile
    45                             def f():
    46    107.8 MiB      0.0 MiB       a, b = B(), B()
    47                                 #here some memory increase
    48                                 #and this mem. is not coupled
    49    126.8 MiB     19.1 MiB       a.foo.append(np.arange(5000000))
    50    149.7 MiB     22.9 MiB       b.foo.append(np.arange(6000000))
    51    149.7 MiB      0.0 MiB       return a,b


[array([      0,       1,       2, ..., 5999997, 5999998, 5999999])] [array([      0,       1,       2, ..., 4999997, 4999998, 4999999])]
Filename: F:/MegaSync/Desktop/python_simulate_pointer_with_class.py

Line #    Mem usage    Increment   Line Contents
================================================
    52    111.6 MiB      0.0 MiB   @profile
    53                             def g():
    54                                 #clearing b.foo list
    55                                 #do not clear a.foo
    56     92.5 MiB    -19.1 MiB       b.foo.clear()
    57     92.5 MiB      0.0 MiB       return a,b


[] [array([      0,       1,       2, ..., 5999997, 5999998, 5999999])]
Filename: F:/MegaSync/Desktop/python_simulate_pointer_with_class.py

Line #    Mem usage    Increment   Line Contents
================================================
    58     92.5 MiB      0.0 MiB   @profile
    59                             def h():
    60                                 #and here memory increse again ;/
    61    107.8 MiB     15.3 MiB       b.foo=np.arange(10000000)
    62                                 #memory inc. when b.foo is replaced
    63    145.9 MiB     38.1 MiB       a.foo.append(np.arange(10000000))
    64    145.9 MiB      0.0 MiB       return b,a


[array([      0,       1,       2, ..., 9999997, 9999998, 9999999])] [      0       1       2 ..., 9999997 9999998 9999999]

추신 : 나는 (Python으로 시작된) 자기 학습 프로그래밍이므로 내가 틀렸다면 나를 미워하지 마십시오. 내 직감이 그렇게 생각하게 해줬으니 나를 미워하지 마라!


부정적이며 포인터가 없습니다. 언어가 설계된 방식으로 필요하지 않아야합니다. 그러나 ctypes 모듈을 사용하여 사용할 수 있다는 불쾌한 소문을 들었 습니다. 나는 그것을 사용하지 않았지만 그것은 나에게 지저분한 냄새가 난다.

참조 URL : https://stackoverflow.com/questions/1145722/simulating-pointers-in-python

반응형