Моделирование указателей в 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 ответов:
Это можно сделать явно.
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 модуль для их использования. Я не использовал его, но он пахнет грязно для меня.