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;
}
form.data['field']
とform.field.value
に常に同じ値を持たせたい
これは、装飾名とインデックス付けを伴うため、実行可能です。つまり、barenamesとは異なる構成要素barenamesa
およびb
は、要求しているものであり、要求に応じて完全に不可能です。なぜ不可能なものを求めるandあなたが実際に(可能性のある)ものと完全に異なるwant?!
たぶん、あなたは、ベアネームと装飾名がどれほど劇的に異なるかを理解していないでしょう。 barename a
を参照すると、a
がこのスコープで最後にバインドされたオブジェクト(または、このスコープでバインドされていない場合は例外)を正確に取得しています。これは、Python破壊できない可能性があること。 decoratedname x.y
を参照するときは、オブジェクト(x
が参照するオブジェクト)に「y
属性」を指定するように求めています。 、オブジェクトは完全に任意の計算を実行できます(また、インデックス付けは非常に似ています:また、応答で任意の計算を実行できます)。
さて、あなたの「実際の要求」の例は、それぞれ2つのレベルのインデックス付けまたは属性取得が関係しているので、不思議です。したがって、あなたが切望する微妙さは多くの方法で導入できます。たとえば、value
以外に、form.field
には他にどのような属性がありますか?それ以上の.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])
assignmentsそのような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の「ポインタ」の感覚にほぼ似ていますが、そのような微妙さはインデックス付けでしか機能しないことを理解することが重要ですおよび/または装飾された名前、neverあなたが最初に尋ねたように裸の名前で!
その行だけを変更する方法はありません。できるよ:
a = [1]
b = a
a[0] = 2
b[0]
それはリストを作成し、aに参照を割り当て、次にbも、a参照を使用して最初の要素を2に設定し、b参照変数を使用してアクセスします。
それはバグではなく、機能です:-)
Pythonで「=」演算子を見るときは、割り当てに関して考えないでください。物を割り当てるのではなく、バインドします。 =はバインディング演算子です。
したがって、コードでは、値1に名前を付けています。次に、「a」の値に名前を付けます:b。次に、値2を名前「a」にバインドします。この操作では、bにバインドされた値は変更されません。
Cに似た言語から来るので混乱する可能性がありますが、慣れると、コードをより明確に読んで推論するのに役立つことがわかります。「b」という名前の値は、明示的に変更します。また、「これをインポート」を行うと、PythonのZenが明示的であることが暗黙的であるよりも優れていることがわかります。
Haskellなどの関数型言語もこのパラダイムを使用しており、堅牢性の点で大きな価値があることに注意してください。
はい! Pythonのポインターとして変数を使用する方法があります!
回答の多くが部分的に間違っていたと言って申し訳ありません。原則として、すべてのequal(=)割り当てはメモリアドレスを共有します(id(obj)関数を確認します)が、実際にはそうではありません。 equal( "=")動作が最終的にメモリスペースのコピーとして機能する変数があります。主に単純なオブジェクト(たとえば "int"オブジェクト)とそうでないもの(たとえば "list"、 "dict"オブジェクト) 。
ポインターの割り当ての例を次に示します
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では、Explorerパネルは通常、ポインターメカニズムオブジェクトの定義のメモリアドレス( "@axbbbbbb ...")のように見えます。
トピックで調査することをお勧めします。このトピックについてもっとよく知っている人はたくさんいます。 (「ctypes」モジュールを参照)。お役に立てば幸いです。オブジェクトの有効活用をお楽しみください!よろしく、ホセ・クレスポ
ある観点から見ると、everythingはPythonのポインターです。この例は、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
をオーバーロードします。
id(1)
1923344848 # identity of the location in my memory
>> a = 1
>> b = a # or equivalently b = 1, because 1 is immutable
>> id(a)
1923344848
>> id(b)
1923344848
ご覧のとおり、a
とb
は、同じオブジェクト1
を参照する単なる名前です。後でa = 2
を作成する場合、名前a
を別のオブジェクト2
に再割り当てしますが、b
ではなく、1
を引き続き参照します。
>> id(2)
1923344880
>> a = 2
>> id(a)
1923344880 # same as id(2)
>> id(b)
1923344848 # same as id(1)
可変オブジェクトがあった場合はどうなりますか?
>> id([1])
328817608
>> id([1])
328664968 # different
>> a = [1]
>> id(a)
328817800
>> id(a)
328817800 # same as before
>> b = a # not equivalent to b = [1]
>> id(b)
328817800 # same as id(a)
ここで、名前a
およびb
によって同じリストオブジェクトを参照しています。このリストは変更できますが、同じオブジェクトのままであり、a
とb
は両方とも引き続き参照します
>> a[0] = 2
>> a
[2]
>> b
[2]
>> id(a)
328817800 # same as before
>> id(b)
328817800 # same as before
私は、効果的に、Pythonでポインターをエミュレートする方法として、次の単純なクラスを作成しました。
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)
使用例は次のとおりです(jupyterノートブックページから)。
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]
もちろん、オブジェクトの辞書項目または属性に対してこの作業を行うことも簡単です。 globals()を使用して、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が要求したことを(お勧めできない場合)実行できることを示しています。
もちろん、この例はかなり無意味です。しかし、このクラスは、開発したアプリケーションで有用であることがわかりました。その動作は、さまざまなタイプの多数のユーザー設定可能な数学パラメーターによって制御される数学モデルです(コマンドライン引数に依存するため不明です)コンパイル時)。そして、何かへのアクセスがParameterオブジェクトにカプセル化されると、そのようなオブジェクトはすべて均一な方法で操作できます。
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