我知道Python没有指针,但有没有办法有这个收益率2,而不是
>>> a = 1
>>> b = a # modify this line somehow so that b "points to" a
>>> a = 2
>>> b
1
Run Code Online (Sandbox Code Playgroud)
?
这是一个例子:我希望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
Run Code Online (Sandbox Code Playgroud)
输出:
GeorgeGeorgeRalphRalph
Run Code Online (Sandbox Code Playgroud)
或者在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;
}
Run Code Online (Sandbox Code Playgroud)
Mat*_*hen 48
你无法改变那条线.你可以做:
a = [1]
b = a
a[0] = 2
b[0]
Run Code Online (Sandbox Code Playgroud)
这会创建一个列表,将引用分配给a,然后b也使用a引用将第一个元素设置为2,然后使用b引用变量进行访问.
Ale*_*lli 47
我希望
form.data['field']并form.field.value始终拥有相同的价值
这是可行的,因为它涉及修饰的名和索引-即,完全由不同结构barenames a和b你问一下,并为您的要求是完全不可能的.为什么要求一些不可能的东西,与你真正想要的(可能的)东西完全不同?
也许你没有意识到裸名和装饰名称有多么不同.当你引用一个裸名时a,你得到的是该对象a最后一次绑定到这个范围内(或者如果它没有绑定在这个范围内的例外) - 这是Python的一个深层次的基本方面,它可以可能会被颠覆.当你引用一个装饰名称时x.y,你要求一个对象(该对象x引用)请提供" y属性" - 并且为了响应该请求,该对象可以执行完全任意的计算(并且索引非常相似:它还允许在响应中执行任意计算).
现在,您的"实际需求"示例是神秘的,因为在每种情况下都涉及两个级别的索引或属性获取,因此您渴望的微妙之处可以通过多种方式引入.还有什么其他属性form.field,例如,除此之外value?没有进一步的.value计算,可能性包括:
class Form(object):
...
def __getattr__(self, name):
return self.data[name]
Run Code Online (Sandbox Code Playgroud)
和
class Form(object):
...
@property
def data(self):
return self.__dict__
Run Code Online (Sandbox Code Playgroud)
的存在.value表明采摘第一种形式,加上那种-的无用的包装器:
class KouWrap(object):
def __init__(self, value):
self.value = value
class Form(object):
...
def __getattr__(self, name):
return KouWrap(self.data[name])
Run Code Online (Sandbox Code Playgroud)
如果这样的赋值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)
Run Code Online (Sandbox Code Playgroud)
后一个例子在Python中大致与它似乎想要的"指针"一样接近 - 但是理解这些细微之处只能用于索引和/或装饰名称是至关重要的,从不像你最初问的那样有了昵称!
Dav*_*rks 32
这不是一个错误,这是一个功能 :-)
当你在Python中查看'='运算符时,不要考虑赋值.你没有分配东西,你绑定它们.=是绑定运算符.
所以在你的代码中,你给值1一个名字:a.然后,您将'a'中的值赋予名称:b.然后,您将值2绑定到名称"a".绑定到b的值在此操作中不会更改.
来自类C语言,这可能会令人困惑,但是一旦你习惯了它,你会发现它可以帮助你更清楚地阅读和推理你的代码:名称为'b'的值不会改变,除非你明确地改变它.如果你做'导入',你会发现Python的Zen声明Explicit比隐含更好.
还要注意,Haskell等函数式语言也使用这种范式,在鲁棒性方面具有很大价值.
Jos*_*ios 27
是! 有一种方法可以在python中使用变量作为指针!
很抱歉,许多答案都是错误的.原则上,每个相等(=)赋值共享内存地址(检查id(obj)函数),但实际上并非如此.有些变量的相等("=")行为在上一个术语中作为内存空间的副本工作,主要是在简单对象(例如"int"对象)中,而其他变量则不在(例如"list","dict"对象) .
这是一个指针分配的例子
dict1 = {'first':'hello', 'second':'world'}
dict2 = dict1 # pointer assignation mechanism
dict2['first'] = 'bye'
dict1
>>> {'first':'bye', 'second':'world'}
Run Code Online (Sandbox Code Playgroud)
以下是复制分配的示例
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
Run Code Online (Sandbox Code Playgroud)
指针分配是一种非常有用的混叠工具,在不浪费额外内存的情况下,在某些情况下执行舒适的代码,
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
Run Code Online (Sandbox Code Playgroud)
但是必须要注意这种用法以防止代码错误.
总而言之,默认情况下,一些变量是裸名(简单对象,如int,float,str,...),有些变量是指定它们之间的指针(例如dict1 = dict2).如何识别它们?试试这个实验.在具有可变资源管理器面板的IDE中,通常看起来是指针机制对象定义中的内存地址("@axbbbbbb ...").
我建议调查一下这个话题.有很多人肯定会对这个话题有更多的了解.(参见"ctypes"模块).我希望它有所帮助.享受好物品的使用!此致JoséCrespo
dan*_*n04 12
从一个角度来看,一切都是Python中的指针.您的示例与C++代码非常相似.
int* a = new int(1);
int* b = a;
a = new int(2);
cout << *b << endl; // prints 1
Run Code Online (Sandbox Code Playgroud)
(更接近的等价物将使用某种类型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
Run Code Online (Sandbox Code Playgroud)
正如您所看到的那样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)
Run Code Online (Sandbox Code Playgroud)
如果你有一个可变对象会发生什么?
>> 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)
Run Code Online (Sandbox Code Playgroud)
现在,您通过名称a和引用相同的列表对象b.您可以改变此列表,但它将保持相同的对象,a并且b将继续引用它
>> a[0] = 2
>> a
[2]
>> b
[2]
>> id(a)
328817800 # same as before
>> id(b)
328817800 # same as before
Run Code Online (Sandbox Code Playgroud)
这是一个Python指针(与C/C++不同)
>>> a = lambda : print('Hello')
>>> a
<function <lambda> at 0x0000018D192B9DC0>
>>> id(a) == int(0x0000018D192B9DC0)
True
>>> from ctypes import cast, py_object
>>> cast(id(a), py_object).value == cast(int(0x0000018D192B9DC0), py_object).value
True
>>> cast(id(a), py_object).value
<function <lambda> at 0x0000018D192B9DC0>
>>> cast(id(a), py_object).value()
Hello
Run Code Online (Sandbox Code Playgroud)