python变量是指针?

Lio*_*ior 66 python variables pointers identifier

据我所知,Python中的变量只是指针.

基于此规则,我可以假设此代码段的结果:

i = 5
j = i
j = 3 
print(i)
Run Code Online (Sandbox Code Playgroud)

会的3.但是我得到了一个意想不到的结果,是的5.

此外,我的Python书确实涵盖了这个例子:

i = [1,2,3]
j = i
i[0] = 5
print(j)
Run Code Online (Sandbox Code Playgroud)

结果将是[5,2,3].

我理解错了什么?

Joh*_*ooy 83

我们称之为参考.他们这样工作

i = 5     # create int(5) instance, bind it to i
j = i     # bind j to the same int as i
j = 3     # create int(3) instance, bind it to j
print i   # i still bound to the int(5), j bound to the int(3)
Run Code Online (Sandbox Code Playgroud)

实施小额投资,但这对此解释并不重要

i = [1,2,3]   # create the list instance, and bind it to i
j = i         # bind j to the same list as i
i[0] = 5      # change the first item of i
print j       # j is still bound to the same list as i
Run Code Online (Sandbox Code Playgroud)

  • @yuqli在python中,一切都是对象,包括数字.由于经常使用小数(-5,256),因此它们在CPython中被"实习"或缓存.因此,每次输入"40"时,都会在内存中引用相同的对象.要看到这种类型a,b = 256并测试`a是b`.现在尝试使用a,b = 257.请参阅:/sf/answers/79579671/和https://www.codementor.io/python/tutorial/stack-overflow-martijn-pieters-python-optimization (5认同)
  • 嗨约翰,你的意思是'小in被拘禁'?谢谢! (3认同)
  • 以我的经验,在Python开发人员中更常见的称呼它们为[“ names”](https://docs.python.org/3/reference/lexical_analysis.html#identifiers)。术语“引用”带有不必要的C包,可能会使Python(*语言*)偏向于CPython(*实现*),而CPython恰好使用了引用计数。 (2认同)
  • 如果您读过这个答案并想“好吧,但是我如何制作变量的副本而不是引用它?”,以下是您对列表问题的答案:/sf/ask/182896171/ /10405322 (2认同)

Mar*_*ers 29

变量不是指针.分配给变量时,您将名称绑定到对象.从那时起,您可以使用名称引用该对象,直到该名称被反弹.

在第一个示例中,名称i绑定到值5.绑定不同的值对名称j没有任何影响i,所以当你以后打印值i的值仍然是5.

在第二个例子中,你地结合i,并j同一个列表对象.修改列表的内容时,无论使用哪个名称来引用列表,都可以看到更改.

请注意,如果您说"两个列表都已更改",那将是不正确的.只有一个列表,但它有两个引用它的名称(ij).

相关文档


Aar*_*all 14

Python变量是绑定到对象的名称

来自文档:

名称指的是对象.名称由名称绑定操作引入.程序文本中每次出现的名称都是指在包含该用途的最内层功能块中建立的该名称的绑定.

当你这样做

i = 5
j = i
Run Code Online (Sandbox Code Playgroud)

这和做的一样:

i = 5
j = 5
Run Code Online (Sandbox Code Playgroud)

j不指向i,并且在任务之后,j不知道i存在. j只是绑定到i分配时指向的任何东西.

如果您在同一行上进行了分配,它将如下所示:

i = j = 5
Run Code Online (Sandbox Code Playgroud)

结果将完全相同.

因此,以后做

i = 3
Run Code Online (Sandbox Code Playgroud)

不改变j指向的东西- 你可以交换它 - j = 3不会改变i指向的东西.

您的示例不会取消引用列表

所以当你这样做时:

i = [1,2,3]
j = i
Run Code Online (Sandbox Code Playgroud)

这与做到这一点是一样的:

i = j = [1,2,3]
Run Code Online (Sandbox Code Playgroud)

所以i,j两者都指向同一个清单.然后你的例子改变了列表:

i[0] = 5
Run Code Online (Sandbox Code Playgroud)

Python列表是可变对象,因此当您从一个引用更改列表,并从另一个引用中查看它时,您将看到相同的结果,因为它是相同的列表.


Mis*_*agi 7

TLDR:Python 名称的作用类似于具有自动取消/引用的指针,但不允许显式的指针操作。其他目标表示间接寻址,其行为类似于指针。


CPython实现在幕后使用类型的指针PyObject*。这样,可以将名称语义转换为指针操作。关键是将名称与实际对象分开。

示例Python代码同时包含名称(i)和对象(5)。

i = 5  # name `i` refers to object `5`
j = i  # ???
j = 3  # name `j` refers to object `3`
Run Code Online (Sandbox Code Playgroud)

可以将其粗略地翻译为具有单独名称和对象的C代码。

int three=3, five=5;  // objects
int *i, *j;           // names
i = &five;   // name `i` refers to position of object `5`
j = i;       // name `j` refers to referent of `i`
j = &three;  // name `j` refers to position of object `3`
Run Code Online (Sandbox Code Playgroud)

重要的部分是“指针命名”不存储对象!我们没有定义*i = five,但是i = &five。名称和对象彼此独立存在。

名称仅指向内存中的现有对象。

从名称分配到名称时,不交换任何对象!当我们定义时j = i,这等效于j = &five。既不i也不j被连接到另一个。

+- name i -+ -\
               \
                --> + <five> -+
               /    |        5 |
+- name j -+ -/     +----------+
Run Code Online (Sandbox Code Playgroud)

结果,更改一个名称的目标不会影响另一名称。它仅更新特定名称指向的内容。


Python还具有其他类型的类似于名称的元素:属性引用(i.j),订阅(i[j])和切片(i[:j])。与直接引用对象的名称不同,所有三个间接引用对象的元素

示例代码包括名称(i)和预订(i[0])。

i = [1,2,3]  # name `i` refers to object `[1, 2, 3]`
j = i        # name `j` refers to referent of `i`
i[0] = 5     # ???
Run Code Online (Sandbox Code Playgroud)

CPython在内部list使用C PyObject*指针数组。可以再次将其粗略地翻译为具有单独名称和对象的C代码。

typedef struct{
    int *elements[3];
} list;  // length 3 `list` type

int one = 1, two = 2, three = 3, five = 5;
list values = {&one, &two, &three};  // objects
list *i, *j;                         // names
i = &values;             // name `i` refers to object `[1, 2, 3]`
j = i;                   // name `j` refers to referent of `i`
i->elements[0] = &five;  // leading element of `i` refers to object `5`
Run Code Online (Sandbox Code Playgroud)

重要的是我们没有更改任何名称!我们确实更改了i->elements[0],我们的名字都指向了该对象的元素。

现有复合对象的值可以更改。

通过名称更改对象的值时,名称不会更改。双方ij仍指向同一个对象,它的值我们可以改变。

+- name i -+ -\
               \
                --> + <values> -+
               /    |  elements | --> [1, 2, 3]
+- name j -+ -/     +-----------+
Run Code Online (Sandbox Code Playgroud)

中间对象的行为类似于指针,因为我们可以直接更改它指向的对象并从多个名称中引用它。

  • 我真的很喜欢这个答案,但我认为您颠倒了示例中的“i”和“j”分配。您从“i = 5”、“j = 3”开始,然后在帖子的其余部分中颠倒它们。话虽如此,在我看来,这是唯一能够公正地回答OP中的问题并真正解释幕后发生的事情的答案。 (2认同)
  • @jeremyradcliff 感谢您的提醒。现在应该修复了。如果我错过了更多,请告诉我。 (2认同)
  • 这应该是公认的答案!它直接解决了 C 问题。作为一个C程序员,这是我唯一能真正理解的答案。 (2认同)

Kei*_*ith 6

它们不是指针,它们是对象的引用.对象可以是可变的,也可以是不可变的.修改不可变对象时会复制它.可变对象就地改变.整数是一个不可变对象,由i和j变量引用.列表是一个可变对象.

在你的第一个例子中

i=5
# The label i now references 5
j=i
# The label j now references what i references
j=3
# The label j now references 3
print i
# i still references 5
Run Code Online (Sandbox Code Playgroud)

在你的第二个例子中:

i=[1,2,3]
# i references a list object (a mutable object)
j=i
# j now references the same object as i (they reference the same mutable object)
i[0]=5
# sets first element of references object to 5
print j
# prints the list object that j references. It's the same one as i.
Run Code Online (Sandbox Code Playgroud)

  • *“不可变对象在修改时会被复制。”* 这有点自相矛盾。 (2认同)