Моделирование указателей в Python


Я пытаюсь скомпилировать in house language(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 я должен генерировать, чтобы имитировать случай, который я показал выше

мой питон не самый большой, но до сих пор мои исследования не дали ничего многообещающего: (

Я должен отметить, что мы хотим перейти от нашего МГП к более общему языку, поэтому мы действительно не привязаны к Python, если кто-то может предложить другой язык, который может быть более подходящим.

10 52

10 ответов:

Это можно сделать явно.

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

вы можете ознакомиться семантика имен переменных Python с точки зрения C++. Итог:все переменные являются ссылками.

более того, не думайте в терминах переменных, но в терминах объектов, которые могут быть имени.

Если вы компилируете C-подобный язык, скажите:

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

в Python, то все" все в Python является ссылкой " материал является неправильным названием.

это правда, что все в Python является ссылкой, но тот факт, что многие основные типы (ints, strings) являются неизменяемыми, эффективно отменяет это для многих случаев. Там нет прямые способ реализации выше в Python.

теперь вы можете сделать это косвенно: для любого неизменяемого типа оберните его изменчивый тип. Эфемерное решение работает, но я часто просто делаю это:

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

(Я сделал это, чтобы обойти отсутствие "нелокального" Python в 2.х несколько раз.)

Это подразумевает гораздо больше накладных расходов: каждый неизменяемый тип (или каждый тип, если вы не пытаетесь различать) внезапно создает список (или другой объект контейнера), поэтому вы значительно увеличиваете накладные расходы для переменных. По отдельности это не так много, но это будет складываться при применении к целому кодовая база.

вы можете уменьшить это, только обернув неизменяемые типы, но тогда вам нужно будет отслеживать, какие переменные в выходных данных обернуты, а какие нет, поэтому вы можете получить доступ к значению с помощью "a" или "a[0]" соответствующим образом. Он, вероятно, станет волосатым.

является ли это хорошей идеей или нет-зависит от того, почему вы делаете это. Если вы просто хотите что-то запустить виртуальную машину, я бы сказал, что нет. Если вы хотите иметь возможность звонить на существующий язык из Python, Я бы предложил взять вашу существующую виртуальную машину и создать для нее привязки Python, чтобы вы могли получить доступ и позвонить в нее из Python.

почти точно так же, как ephemientответ, который я проголосовал, вы можете использовать встроенный Python свойства

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

еще один, и совершенно сумасшедший вариант будет использовать питона 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

что больше нравится Первоначальный запрос ОП. сумасшедший!

все в Python уже указатели, но это называется "ссылки" в Python. Это перевод вашего кода на 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]

"разыменования" не имеет смысла, так как это все ссылки. Больше ничего нет, так что нечего разыменовывать.

как говорили другие здесь, все переменные Python по существу являются указателями.

ключом к пониманию этого с точки зрения 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]

и здесь у нас есть явное я в классе:

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]

ps: я самостоятельно учусь программированию (начал с Python), поэтому, пожалуйста, не ненавидьте меня, если я ошибаюсь. Это просто моя интуиция, которая позволяет мне думать так что не надо меня ненавидеть!

отрицательно, без указателей. Вы не должны нуждаться в них с тем, как язык разработан. Однако, я слышал неприятный слух, что вы могли бы использовать: ctypes модуль для их использования. Я не использовал его, но он пахнет грязно для меня.