programing

Python의 포인터?

lastmoon 2023. 7. 16. 17:47
반응형

Python의 포인터?

포인터가 건 , 이 수 요?2대신에

>>> a = 1
>>> b = a # modify this line somehow so that b "points to" a
>>> a = 2
>>> b
1

?


다음은 예입니다.나는 되고 싶다.form.data['field']그리고.form.field.value항상 동일한 값을 갖는 것.꼭 필요한 건 아니지만 그래도 좋을 것 같아요.


예를 들어 PHP에서는 다음과 같은 작업을 수행할 수 있습니다.

<?php

class Form {
    public $data = [];
    public $fields;

    function __construct($fields) {
        $this->fields = $fields;
        foreach($this->fields as &$field) {
            $this->data[$field['id']] = &$field['value'];
        }
    }
}

$f = new Form([
    [
        'id' => 'fname',
        'value' => 'George'
    ],
    [
        'id' => 'lname',
        'value' => 'Lucas'
    ]
]);

echo $f->data['fname'], $f->fields[0]['value']; # George George
$f->data['fname'] = 'Ralph';
echo $f->data['fname'], $f->fields[0]['value']; # Ralph Ralph

출력:

GeorgeGeorgeRalphRalph

이상적인


아니면 C++에서 이런 식으로 (이것이 옳다고 생각하지만, 내 C++은 녹슬었습니다):

#include <iostream>
using namespace std;

int main() {
    int* a;
    int* b = a;
    *a = 1;
    cout << *a << endl << *b << endl; # 1 1

    return 0;
}

그 선만 바꿔서 그렇게 할 수는 없습니다.할 수 있는 일:

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

그러면 목록이 생성되고 참조가 a에 할당된 다음 b도 참조를 사용하여 첫 번째 요소를 2로 설정한 다음 참조 변수를 사용하여 액세스합니다.

나는 되고 싶다.form.data['field']그리고.form.field.value

이것은 장식된 이름과 인덱싱을 포함하기 때문에 실현 가능합니다. 즉, 베어 이름과 완전히 다른 구조입니다. a그리고.b당신이 묻고 있는 것, 그리고 당신의 요청은 완전히 불가능하기 때문입니다.왜 당신이 실제로 원하는 (가능한) 것과는 전혀 다른 불가능한 것을 요구합니까?!

아마도 여러분은 베어 네임과 장식된 네임이 얼마나 극적으로 다른지 깨닫지 못할 것입니다.는 당신베언급때할을임어네이▁when때할.a하게 목적어를 있습니다.a이 범위에서 마지막으로 바인딩되었습니다(또는 이 범위에서 바인딩되지 않은 경우 예외). 이것은 Python의 매우 깊고 근본적인 측면이므로 뒤집을 수 없습니다.당신이 장식된 이름을 언급할 때.x.y어떤: 목적어: 목적어: 목적어: 목적어: 목적어: 목적어: 목적어: 목적어: 목적어: 목적어: 목적어: 목적어: 목적어: 목적어: 목적어: 목적어: 목적어: 목적어)을x를 참조) "더"를 제공하십시오.y속성" -- 그리고 그 요청에 대한 응답으로, 오브젝트는 완전히 임의적인 계산을 수행할 수 있습니다(그리고 인덱싱은 매우 유사합니다: 응답으로 임의적인 계산을 수행할 수도 있습니다).

자, 여러분의 "실제 수요자 데이터"의 예는 신비롭습니다. 각각의 경우 두 가지 수준의 인덱싱 또는 속성 획득이 관련되어 있기 때문입니다. 따라서 여러분이 갈망하는 섬세함이 여러 가지 방식으로 소개될 수 있기 때문입니다.다른 속성은 무엇입니까?form.field예를 들어, 가외에 있다고 가정합니다.value 이상은 필요 ..value계산의 가능성은 다음과 같습니다.

class Form(object):
   ...
   def __getattr__(self, name):
       return self.data[name]

그리고.

class Form(object):
   ...
   @property
   def data(self):
       return self.__dict__

..value는 첫 양식을 할 것을 제안하고 다음과 종류의 포장지를 할 것을 제안합니다.

class KouWrap(object):
   def __init__(self, value):
       self.value = value

class Form(object):
   ...
   def __getattr__(self, name):
       return KouWrap(self.data[name])

만약 그런 과제가 있다면,form.field.value = 23는 또한 또한항설합니다야정에 항목을 있습니다.form.data그러면 포장지는 실제로 더 복잡해져야 하며, 그렇게 쓸모없는 것은 아닙니다.

class MciWrap(object):
   def __init__(self, data, k):
       self._data = data
       self._k = k
   @property
   def value(self):
       return self._data[self._k]
   @value.setter
   def value(self, v)
       self._data[self._k] = v

class Form(object):
   ...
   def __getattr__(self, name):
       return MciWrap(self.data, name)

후자의 예는 Python에서 당신이 원하는 대로 "포인터"의 의미에 거의 가깝습니다. 하지만 그러한 섬세함은 당신이 원래 요청했던 것처럼 절대로 색인화 및/또는 장식된 이름으로만 작동할 수 있다는 것을 이해하는 것이 중요합니다!

버그가 아니라 기능입니다 :-)

Python에서 '=' 연산자를 볼 때, 할당적인 측면에서 생각하지 마세요.당신은 물건을 할당하지 않고 묶습니다.바인딩 연산자입니다.

따라서 코드에서 값 1에 이름 a를 지정합니다.그런 다음 'a'의 값을 b라는 이름으로 지정합니다.그런 다음 값 2를 이름 'a'에 바인딩합니다.이 작업에서 b에 바인딩된 값은 변경되지 않습니다.

C와 같은 언어에서 오는 것은 혼란스러울 수 있지만, 일단 익숙해지면 코드를 더 명확하게 읽고 추론하는 데 도움이 된다는 것을 알게 됩니다: 'b'라는 이름을 가진 값은 명시적으로 변경하지 않는 한 변경되지 않습니다.그리고 만약 당신이 '이것을 가져오기'를 한다면, 당신은 Python의 Zen이 암시적인 것보다 명시적인 것이 더 낫다는 것을 알게 될 것입니다.

또한 Haskell과 같은 기능성 언어도 견고성 측면에서 큰 가치를 가지고 이 패러다임을 사용합니다.

네! 파이썬에서 변수를 포인터로 사용하는 방법이 있습니다!

유감스럽게도 많은 답변들이 부분적으로 틀렸습니다.원칙적으로 모든 equal(=) 할당은 메모리 주소를 공유하지만(id(obj) 함수를 확인하십시오) 실제로는 그렇지 않습니다.동일한 ("=") 동작이 마지막으로 메모리 공간의 복사본으로 작동하는 변수가 있으며, 대부분 단순 객체(예: "int" 객체)와 그렇지 않은 다른 객체(예: "list", "module" 객체)에서 작동합니다.

포인터 할당의 예는 다음과 같습니다.

dict1 = {'first':'hello', 'second':'world'}
dict2 = dict1 # pointer assignation mechanism
dict2['first'] = 'bye'
dict1
>>> {'first':'bye', 'second':'world'}

다음은 복사 할당의 예입니다.

a = 1
b = a # copy of memory mechanism. up to here id(a) == id(b)
b = 2 # new address generation. therefore without pointer behaviour
a
>>> 1

포인터 할당은 편안한 코드를 수행하기 위한 특정 상황에서 여분의 메모리를 낭비하지 않고 앨리어싱에 꽤 유용한 도구입니다.

class cls_X():
   ...
   def method_1():
      pd1 = self.obj_clsY.dict_vars_for_clsX['meth1'] # pointer dict 1: aliasing
      pd1['var4'] = self.method2(pd1['var1'], pd1['var2'], pd1['var3'])
   #enddef method_1
   ...
#endclass cls_X

그러나 코드 실수를 방지하기 위해서는 이 사용법을 알아야 합니다.

결론적으로 기본적으로 일부 변수는 베어 이름(int, float, str,...)이고 일부 변수는 그들 사이에 할당될 때 포인터입니다(예: dict1 = dict2).그들을 어떻게 인식합니까?그냥 그들과 함께 이 실험을 해보세요.가변 탐색기 패널이 있는 IDE에서는 일반적으로 메모리 주소("@axbbbbb..".")이(가) 포인터로 표시됩니다.

저는 그 주제에 대해 조사할 것을 제안합니다.확실히 이 주제에 대해 훨씬 더 많이 알고 있는 사람들이 많습니다.("ctypes" 모듈 참조).도움이 되길 바랍니다.그 물건들을 잘 사용하세요!안녕하세요, 호세 크레스포

>> id(1)
1923344848  # identity of the location in memory where 1 is stored
>> id(1)
1923344848  # always the same
>> a = 1
>> b = a  # or equivalently b = 1, because 1 is immutable
>> id(a)
1923344848
>> id(b)  # equal to id(a)
1923344848

당신이 볼 수 있듯이.a그리고.b동일한 불변 객체(int)를 참조하는 두 개의 다른 이름일 뿐입니다.1나중에 글을 쓰면,a = 2 할당합니다.a다른 개체(int)로2 러나그나b해서 해참니다합조계를 합니다.1:

>> id(2)
1923344880
>> a = 2
>> id(a)
1923344880  # equal to id(2)
>> b
1           # b hasn't changed
>> id(b)
1923344848  # equal to id(1)

만약 당신이 한 개체를 가지고 요?[1]?

>> id([1])
328817608
>> id([1])
328664968  # different from the previous id, because each time a new list is created
>> a = [1]
>> id(a)
328817800
>> id(a)
328817800 # now same as before
>> b = a
>> id(b)
328817800  # same as id(a)

같은 다동목개(목록) 를시고참체조록(목록)를 하고 있습니다.[1] a그리고.b하지만 이제 이 목록이 동일한 개체로 남아 있는 동안 변형될 수 있습니다.a,b 다 참조할 입니다.

>> a[0] = 2
>> a
[2]
>> b
[2]
>> id(a)
328817800  # same as before
>> id(b)
328817800  # same as before

한 관점에서 보면, 모든 것은 파이썬의 포인터입니다.예제는 C++ 코드와 매우 유사하게 작동합니다.

int* a = new int(1);
int* b = a;
a = new int(2);
cout << *b << endl;   // prints 1

(더은) 어떤 종류의 (으를shared_ptr<Object>int*.)

다음은 예입니다.form.data['field']와 form.field.value가 항상 동일한 값을 갖도록 합니다.꼭 필요한 건 아니지만 그래도 좋을 것 같아요.

오버로드를 통해 이 작업을 수행할 수 있습니다.__getitem__form.data의 수업.

이것은 파이썬 포인터입니다(c/c++와는 다릅니다).

>>> a = lambda : print('Hello')
>>> a
<function <lambda> at 0x0000018D192B9DC0>
>>> id(a) == int(0x0000018D192B9DC0)
True
>>> from ctypes import cast, py_object
>>> cast(id(a), py_object).value == cast(int(0x0000018D192B9DC0), py_object).value
True
>>> cast(id(a), py_object).value
<function <lambda> at 0x0000018D192B9DC0>
>>> cast(id(a), py_object).value()
Hello

저는 파이썬에서 포인터를 에뮬레이트하는 방법으로 다음과 같은 간단한 클래스를 작성했습니다.

class Parameter:
    """Syntactic sugar for getter/setter pair
    Usage:

    p = Parameter(getter, setter)

    Set parameter value:
    p(value)
    p.val = value
    p.set(value)

    Retrieve parameter value:
    p()
    p.val
    p.get()
    """
    def __init__(self, getter, setter):
        """Create parameter

        Required positional parameters:
        getter: called with no arguments, retrieves the parameter value.
        setter: called with value, sets the parameter.
        """
        self._get = getter
        self._set = setter

    def __call__(self, val=None):
        if val is not None:
            self._set(val)
        return self._get()

    def get(self):
        return self._get()

    def set(self, val):
        self._set(val)

    @property
    def val(self):
        return self._get()

    @val.setter
    def val(self, val):
        self._set(val)

다음은 주피터 노트북 페이지의 사용 예입니다.

l1 = list(range(10))
def l1_5_getter(lst=l1, number=5):
    return lst[number]

def l1_5_setter(val, lst=l1, number=5):
    lst[number] = val

[
    l1_5_getter(),
    l1_5_setter(12),
    l1,
    l1_5_getter()
]

Out = [5, None, [0, 1, 2, 3, 4, 12, 6, 7, 8, 9], 12]

p = Parameter(l1_5_getter, l1_5_setter)

print([
    p(),
    p.get(),
    p.val,
    p(13),
    p(),
    p.set(14),
    p.get()
])
p.val = 15
print(p.val, l1)

[12, 12, 12, 13, 13, None, 14]
15 [0, 1, 2, 3, 4, 15, 6, 7, 8, 9]

물론 개체의 딕트 항목이나 속성에 대해서도 이 작업을 쉽게 수행할 수 있습니다.OP가 요청한 것을 글로벌()을 사용하여 수행하는 방법도 있습니다.

def setter(val, dict=globals(), key='a'):
    dict[key] = val

def getter(dict=globals(), key='a'):
    return dict[key]

pa = Parameter(getter, setter)
pa(2)
print(a)
pa(3)
print(a)

이렇게 하면 2개, 그 다음에 3개가 인쇄됩니다.

이러한 방식으로 글로벌 네임스페이스를 엉망으로 만드는 것은 일종의 끔찍한 아이디어이지만, OP가 요청한 것을 수행하는 것이 (권장하지 않을 경우) 가능하다는 것을 보여줍니다.

물론 그 예는 상당히 무의미합니다.하지만 저는 이 클래스가 제가 개발한 응용 프로그램에서 유용하다는 것을 알게 되었습니다. 다양한 유형의 사용자 설정 수학적 매개 변수에 의해 동작이 제어되는 수학적 모델입니다(명령줄 인수에 의존하기 때문에 컴파일 시에는 알 수 없음).매개 변수 개체에 액세스할 수 있게 되면 모든 개체를 동일한 방식으로 조작할 수 있습니다.

비록 이것이 C나 C++ 포인터처럼 보이지는 않지만, 이것은 제가 C++로 글을 쓰고 있었다면 포인터로 해결했을 문제를 해결하는 것입니다.

다음 코드는 C에서 포인터의 동작을 정확하게 에뮬레이트합니다.

from collections import deque # more efficient than list for appending things
pointer_storage = deque()
pointer_address = 0

class new:    
    def __init__(self):
        global pointer_storage    
        global pointer_address

        self.address = pointer_address
        self.val = None        
        pointer_storage.append(self)
        pointer_address += 1


def get_pointer(address):
    return pointer_storage[address]

def get_address(p):
    return p.address

null = new() # create a null pointer, whose address is 0    

다음은 사용 예입니다.

p = new()
p.val = 'hello'
q = new()
q.val = p
r = new()
r.val = 33

p = get_pointer(3)
print(p.val, flush = True)
p.val = 43
print(get_pointer(3).val, flush = True)

이제 개인 라이브러리에서 찾은 포인터 삭제 옵션을 포함하여 보다 전문적인 코드를 제공해야 합니다.

# C pointer emulation:

from collections import deque # more efficient than list for appending things
from sortedcontainers import SortedList #perform add and discard in log(n) times


class new:      
    # C pointer emulation:
    # use as : p = new()
    #          p.val             
    #          p.val = something
    #          p.address
    #          get_address(p) 
    #          del_pointer(p) 
    #          null (a null pointer)

    __pointer_storage__ = SortedList(key = lambda p: p.address)
    __to_delete_pointers__ = deque()
    __pointer_address__ = 0 

    def __init__(self):      

        self.val = None 

        if new.__to_delete_pointers__:
            p = new.__to_delete_pointers__.pop()
            self.address = p.address
            new.__pointer_storage__.discard(p) # performed in log(n) time thanks to sortedcontainers
            new.__pointer_storage__.add(self)  # idem

        else:
            self.address = new.__pointer_address__
            new.__pointer_storage__.add(self)
            new.__pointer_address__ += 1


def get_pointer(address):
    return new.__pointer_storage__[address]


def get_address(p):
    return p.address


def del_pointer(p):
    new.__to_delete_pointers__.append(p)

null = new() # create a null pointer, whose address is 0

는 어떤 도 가다른답이어답유떤도변는제올을 사용하지 않기 입니다.locals()기능과 그들이 해야 할 일을 정확히 하지 못하는 많은 거대한 클래스들이 있습니다. 즉, 뾰족한 변수 자체를 직접적으로 변경하는 것입니다.

포인터는 항상 다른 변수와 동일한 변수가 아니라 다른 변수로 연결되는 변수입니다.즉, 포인터에 의해 직접 또는 간접적으로(예: 포인터에 의해) 포인터가 변경되어도 포인터가 변경되지 않습니다.

실제로 한 줄의 코드로 완전히 작동하는 포인터를 만들 수는 없지만, 몇 가지 연구 후에 그것은 그렇게 어렵지 않은 것으로 밝혀졌습니다.


모든 에지 케이스를 작동시키려면 적어도 두 가지 기능이 있어야 합니다.

  1. 모든 범위의 유효한 변수 이름이 작동해야 합니다.
  2. 매우 논리적일 수도 있지만 포인터는 항상 가리켜야 합니다!

기능 1을 작동시키려면 기능을 통해 변수를 생성, 변경 또는 삭제하는 방법을 찾아야 합니다.은 이는다통가다니능을 통해 합니다.locals()기능.이 함수는 다음을 반환합니다.dict현재 범위의 모든 변수를 포함합니다. 이 이것을 ,dict변수도 변경됩니다.그래서:

a = 0 # locals()["a"] == 0
lcs = locals() # lcs == {..., "a": 0, ...}
lcs["a"] = 1 # So a == 1 now
print(a) # will print 1

따라서 함수를 통해 변수를 생성, 변경 또는 삭제하는 방법은 다음과 같습니다.

locals().update({"name": "value"}) # create var 'name' with value 'value'
locals().update({"name": "other value"}) # change value of var 'name' to 'other value'
locals().pop("name") # delete var 'name'

저는 오랫동안 이 점에 집착해 왔습니다. 왜냐하면 변수의 값을 얻기 위해서는 항상 함수를 호출해야 하기 때문입니다.

포인터 자체가 그 함수일 수 있다는 것을 알기 전까지는! 포인터는 변수의 함수입니다.C의 포인터에는 별표가 있기 때문에 일반 변수와 다른 것이 몇 개 있으면 큰 문제가 되지 않는다는 것을 깨달았을 때 그 아이디어를 얻었습니다.그러면 큰 스크립트를 작성하거나 가져올 필요도 없습니다.


그래서 세미 포인터를 반환하는 함수를 만들었습니다.

def pointer(name, lcs: dict):
    return lambda *args: (lcs.get(name)) if len(args) == 0 else (lcs.update({name: args[0]}))  # if there are no args, get the value of the pointed variable, else, set the value

이 기능의 사용:

a = 0 # set a to 0

# create the pointer:
b = pointer("a", locals())  # locals() is to make sure that the function only modifies the current scope

a = 1 # set a to 1

print(b) # will print <function add_pointer.<locals>.<lambda> at 0x000001DC04C39D00>
print(b()) # will print 1

b(2) # set a to 2
print(a) # will print 2

두 줄의 추가 코드입니다!

제 댓글이 도움이 될지 모르겠지만 사용하고 싶다면요.pointers파이썬에서, 당신은 사용할 수 있습니다.dictionaries

예를 들어 다음과 같이 가정해 보겠습니다.

a = {'value': 1}

b = {'value': 2}

그리고 나서 당신은 a를 2로 바꿨습니다.

a['value'] = 2

print(a) #{'value': 2}

언급URL : https://stackoverflow.com/questions/3106689/pointers-in-python

반응형