Python中的指针?

156 投票
11 回答
414507 浏览
提问于 2025-04-16 00:21

我知道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

ideone


或者在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 个回答

40

这不是个错误,而是个特性 :-)

当你看到Python中的'='这个符号时,不要把它理解为赋值。你并不是在给东西赋值,而是在给它们绑定名字。'='是一个绑定操作符。

在你的代码里,你把数字1给命名为a。接着,你又把'a'里的值命名为b。然后,你把数字2绑定到名字'a'上。在这个过程中,绑定到b的值并没有改变。

如果你之前用过像C这样的语言,可能会觉得有点困惑,但一旦你习惯了这种方式,你会发现它能让你更清晰地阅读和理解代码:名字为'b'的值不会改变,除非你明确地去改变它。而且如果你输入'import this',你会发现Python的哲学里提到,明确的东西比隐含的要好。

另外,像Haskell这样的函数式语言也使用这种方式,这在稳健性方面非常有价值。

54

我希望 form.data['field']form.field.value 始终有相同的值。

这是可以做到的,因为这涉及到装饰名称和索引,也就是说,这和你提到的简单名称 ab 完全不同,而你所要求的事情是完全不可能的。为什么要要求一些不可能的事情,而且和你真正想要的东西完全不同呢?

也许你没有意识到简单名称和装饰名称之间的差别有多大。当你提到简单名称 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 中大致上是你想要的“指针”的感觉——但重要的是要理解,这种细微之处只能通过 索引 和/或 装饰名称 来实现,绝对不可能 用你最初提到的简单名称!

83

你不能仅仅通过修改那一行来实现这个。你可以这样做:

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

这段代码创建了一个列表,并把这个列表的引用(也就是地址)赋值给变量a,然后b也指向同一个列表。接着,它使用a这个引用把列表的第一个元素设置为2,然后通过b这个引用来访问这个元素。

撰写回答