web-dev-qa-db-ja.com

Pythonでのポインターのシミュレーション

社内言語(ihl)をPythonにクロスコンパイルしようとしています。

Ihlの機能の1つは、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 、what Python上記で示したケースをシミュレートするために生成する必要があります

私のPythonは最高ではありませんが、これまでのところ私の探求は有望なものを何も生み出していません:(

Ihlからより一般的な言語への移行を検討しているため、Pythonより適切な他の言語を誰かが提案できる場合、.

53
chollida

これは明示的に行うことができます。

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
78
ephemient

Python C++の観点からの変数名 のセマンティクス:一番下の行:すべての変数は参照です

要点は、変数の観点ではなく、namedの可能性のあるオブジェクトの観点から考えることです。

20
Stephan202

Cライクな言語をコンパイルする場合、次のように言います。

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

pythonの場合、「Pythonは参照です」にあるすべてのもの」はすべて間違った呼び名です。

Pythonのすべてが参照ですが、多くのコアタイプ(int、string)が不変であるという事実は、多くの場合これを事実上取り消します。directはありません。上記をPythonで実装する方法。

これで、間接的に行うことができます。不変の型については、変更可能な型にラップします。 Ephemientのソリューションは機能しますが、私はしばしばこれを行うだけです:

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

(これは、Pythonの2.xでの「非ローカル」の欠如を数回回避するために行いました。)

これはより多くのオーバーヘッドを意味します:すべての不変型(または区別しようとしない場合はすべての型)が突然リスト(または別のコンテナーオブジェクト)を作成するため、変数のオーバーヘッドが大幅に増加します。個々には、それほど多くはありませんが、コードベース全体に適用すると、合計されます。

不変型のみをラップすることでこれを減らすことができますが、出力内のどの変数がラップされ、どの変数がラップされていないかを追跡する必要があるため、「a」または「a [0]」で値にアクセスできます適切に。おそらく毛むくじゃらになるでしょう。

これが良いアイデアであるかどうかについては、あなたがそれをしている理由に依存します。 VMを実行したいだけなら、私はノーと言う傾向があります。 Pythonから既存の言語を呼び出すことができるようにするには、既存のVMを取得してPythonバインディングを作成することをお勧めします。 Pythonからアクセスして呼び出すことができます。

14
Glenn Maynard

ephemientanswer とほぼ同じですが、投票しましたが、Pythonの組み込み property 関数を使用できます。 ephemientの回答のrefクラスとほぼ同様のことを行いますが、getおよびsetメソッドを使用してrefインスタンスにアクセスすることを強制される代わりに、クラス定義でpropertiesとして割り当てたインスタンスの属性を呼び出すだけです。 From Python docs(ただし、[〜#〜] 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.")

両方のメソッドは、globalに頼らずに、Cポインターのように機能します。たとえば、ポインターを受け取る関数がある場合:

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の元のリクエストに似ています。クレイジー!

9
Mark Mikofski

ここで他の人が言ったように、すべてのPython変数は本質的にポインターです。

Cの観点からこれを理解するための鍵は、多くのid()関数によってunknownを使用することです。変数が指すアドレスを示します。

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

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

>>> id(b)
28354600
4
Unknown

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]

all参照であるため、「参照解除」は意味がありません。他に何もありませんので、参照するものはありません。

3
Lennart Regebro

これは間抜けですが、考え...

# 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

しかし、ポインターの算術演算などはありません。また、他のどの問題に遭遇するかもわかりません。

1
Anon
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
0
Jeremy Banks

この例は短く明確であると思います。

ここに暗黙のリストを持つクラスがあります:

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]

ps:私はプログラミングを自習しています(Pythonで始めました)ので、間違っていても嫌いにならないでください。そのように考えさせてくれるのはまさに私の直観です。

0
user1839053