我正在尝试将内部语言(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来模拟我上面显示的情况
我的Python并不是最好的,但到目前为止,我的探索还没有产生任何有希望的东西:(
我应该指出,我们正在寻求从我们的ihl转向更常用的语言,因此如果有人可以建议另一种更适合的语言,我们就不会真正与Python挂钩。
答案 0 :(得分:78)
这可以明确地完成。
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
答案 1 :(得分:20)
您可能需要阅读Semantics of Python variable names from a C++ perspective。底线:所有变量都是参考。
更重要的是,不要考虑变量,而是根据可以命名的对象。
答案 2 :(得分:14)
如果您正在编译类C语言,请说:
func()
{
var a = 1;
var *b = &a;
*b = 2;
assert(a == 2);
}
进入Python,然后所有“Python中的所有东西都是参考”的东西都是用词不当。
确实,Python中的所有内容都是一个引用,但许多核心类型(整数,字符串)不可变的事实在很多情况下都会有效地解除这一点。在Python中没有直接方式来实现上述功能。
现在,您可以间接地执行此操作:对于任何不可变类型,将其包装为可变类型。 Ephemient的解决方案有效,但我经常这样做:
a = [1]
b = a
b[0] = 2
assert a[0] == 2
(我这样做是为了解决Python在2.x中缺少“非局部”几次。)
这意味着更多的开销:每个不可变类型(或者每个类型,如果你不试图区分)突然创建一个列表(或另一个容器对象),所以你会显着增加变量的开销。单独地,它并不是很多,但是当它应用于整个代码库时它会加起来。
你可以通过只包装不可变类型来减少这种情况,但是你需要跟踪输出中的哪些变量被包装,哪些不是,所以你可以用“a”或“a [来访问” 0]“恰当。它可能会变得毛茸茸。
至于这是否是一个好主意 - 这取决于你为什么这样做。如果你只是想要运行VM,我倾向于拒绝。如果您希望能够从Python调用现有语言,我建议您使用现有的VM并为其创建Python绑定,以便您可以从Python访问和调用它。
答案 3 :(得分:9)
几乎与我投票的ephemient answer完全相同,您可以使用Python的内置property函数。它会在ephemient的答案中做类似于ref
类的事情,除了现在,而不是被迫使用get
和set
方法访问ref
实例,你只需调用您在类定义中指定为属性的实例的属性。从Python文档(除了我将 C 更改为 ptr ):
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的原始请求。神经病!
答案 4 :(得分:4)
正如其他人所说,所有Python变量本质上都是指针。
从C角度理解这一点的关键是使用许多id()函数的unknown。它告诉你变量指向的地址。
>>> a = [1,2]
>>> id(a)
28354600
>>> b = a
>>> id(a)
28354600
>>> id(b)
28354600
答案 5 :(得分:3)
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]
“解除引用”毫无意义,因为它是所有引用。没有别的东西,所以没有什么可以取消引用。
答案 6 :(得分:1)
这很傻,但想到了......
# 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
但是没有指针算术等等,也没有说明你可能遇到的其他问题......
答案 7 :(得分:0)
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
答案 8 :(得分:0)
我认为这个例子很简短明了。
这里我们有隐式列表的类:
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开始)所以如果我错了请不要恨我。它只是我的直觉,让我这么想,所以不要恨我!
答案 9 :(得分:-2)
否定,没有指针。您不应该按照语言的设计方式来使用它们。但是,我听到一个令人讨厌的谣言,你可以使用:ctypes模块来使用它们。我没有使用它,但它对我来说闻起来很混乱。