Python中的指针?
我知道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;
}
11 个回答
这不是个错误,而是个特性 :-)
当你看到Python中的'='这个符号时,不要把它理解为赋值。你并不是在给东西赋值,而是在给它们绑定名字。'='是一个绑定操作符。
在你的代码里,你把数字1给命名为a。接着,你又把'a'里的值命名为b。然后,你把数字2绑定到名字'a'上。在这个过程中,绑定到b的值并没有改变。
如果你之前用过像C这样的语言,可能会觉得有点困惑,但一旦你习惯了这种方式,你会发现它能让你更清晰地阅读和理解代码:名字为'b'的值不会改变,除非你明确地去改变它。而且如果你输入'import this',你会发现Python的哲学里提到,明确的东西比隐含的要好。
另外,像Haskell这样的函数式语言也使用这种方式,这在稳健性方面非常有价值。
我希望
form.data['field']
和form.field.value
始终有相同的值。
这是可以做到的,因为这涉及到装饰名称和索引,也就是说,这和你提到的简单名称 a
和 b
完全不同,而你所要求的事情是完全不可能的。为什么要要求一些不可能的事情,而且和你真正想要的东西完全不同呢?
也许你没有意识到简单名称和装饰名称之间的差别有多大。当你提到简单名称 a
时,你得到的就是在这个范围内 a
最后绑定的对象(如果没有绑定,就会抛出异常)——这是 Python 中一个非常深刻和基本的特性,无法被改变。当你提到一个装饰名称 x.y
时,你是在请求一个对象(x
所指向的对象)提供“y
属性”——作为回应,这个对象可以执行完全任意的计算(索引也是类似的:它也允许在响应中执行任意计算)。
现在,你提到的“实际需求”例子有点神秘,因为在每种情况下都涉及到两个层次的索引或属性获取,所以你想要的细微之处可以通过很多方式引入。比如,form.field
还应该具有什么其他属性,除了 value
呢?如果没有进一步的 .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])
如果像 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 中大致上是你想要的“指针”的感觉——但重要的是要理解,这种细微之处只能通过 索引 和/或 装饰名称 来实现,绝对不可能 用你最初提到的简单名称!
你不能仅仅通过修改那一行来实现这个。你可以这样做:
a = [1]
b = a
a[0] = 2
b[0]
这段代码创建了一个列表,并把这个列表的引用(也就是地址)赋值给变量a,然后b也指向同一个列表。接着,它使用a这个引用把列表的第一个元素设置为2,然后通过b这个引用来访问这个元素。