# 3.5 动态类型

### 3.5.1 变量

在C、C++语言中，如果我们需要使用变量，需要先对变量类型进行声明，而在Python中，我们既不用说明变量的类型，也不用声明变量存在。但是变量在使用前必须被赋值。

对于变量x来说，它在第一次被赋值时创建。也可以说通过赋值，我们创建了变量x。对于变量x来说，变量一旦被创建，并不意味着它的类型就固定了。进一步说，变量永远不会被类型固定，变量永远是通用的。变量通过**引用**特定的对象，可以改变自身数据类型。

### 3.5.2 引用

我们创建的变量都是对对象的引用。要想深入理解这句话的含义，先让我们考虑这样一种情形：为变量x赋值0。

\>>>x=0

Python解释器在完成对变量x赋值的过程中，一共经历了三步：

1. 创建一个值为3的整数对象。
2. 创建一个变量x。如果变量x已经存在，则无需执行此步。
3. 使变量引用在第一步中创建的整数对象。

   变量总是引用对象，而不会出现引用到变量的情况。

   引用是一种关系，这种关系通过内存中的**指针**来实现。当创建变量的时候，解释器就会自动追踪这个变量的引用对象。

   现在我们对x进行多次赋值：

\>>>x=0

\>>>x={1, 2 , 3, 4}

\>>>x=\[1, 2]

\>>>x=”hello world!”

我们首先创建了一个值为0的整数对象，然后创建了一个变量x，使x引用这个整数对象。接着我们使x引用含有元素1， 2， 3， 4的集合对象。最后我们使x引用字符串对象“hello world！”。在这个例子中，我们通过对x进行多次赋值，使x多次引用了不同的对象类型。这也从侧面反映了，变量本身并不对类型进行记忆，实质上，类型在对象中存放。

在Python中，每一个对象都有两个标准的头部信息：**类型标识符**（type desinator）和**引用计数器**（reference counter）。前者标识了对象的类型，后者记录对对象进行回收的时间。

### 3.5.3 垃圾回收

在引用一节中，我们对x进行多次赋值，使其引用不同的对象类型，最终使其指向字符串对象类型。这样的话，我们就有一个疑问：之前我们创建的整型对象，集合对象和列表对象到哪去了？

实质上，这些没有被引用的对象占用的内存被回收了，所以这些对象自然也就消失了。这种自动回收对象空间的技术叫做**垃圾回收**。每当x引用新的对象时，解释器都会对旧对象占用的内存进行回收。这些就空间被放入自由内存空间池，可以被再次利用。

对象中的引用计数器记录了当前引用该对象的变量的数目。一旦这个计数器变为零，就意味着，不再有变量指向这个对象。这时候，解释器就会对这个对象占用的内存空间进行回收。

### 3.5.4 共享引用

当多个变量共同引用一个对象时，就构成了**共享引用**。如果这个对象不支持在原位置修改，那么对变量进行重新赋值就会使变量重新引用新的变量。当所有变量不再引用这个对象时，该对象才会被回收。如果这个对象**支持在原位置进行修改**，对变量进行原位赋值，就会使这个对象发生改变从而影响到所有变量。

例：共享整型引用对象引用

\>>>x=0

\>>>y=x

\>>>x, y

\>>>x=1

\>>>x, y

在上例中，我们先使变量x和y共享为0的整型对象， 然后对x赋值1。此时，x引用了新的值为1的整型变量，y依然引用原有的值为0的整型变量。

我们可以使用身份运算符来确认多变量是否引用到了同一个对象：

例：共享列表引用对象，同时使用身份运算符对判断变量是否引用到同一个对象

\>>>L1=\[1, 2, 3]

\>>>L2=L1

\>>>L1, L2

(\[1, 2, 3], \[1, 2, 3])

\>>>L1=4

\>>>L1, L2, L1 is L2

(4, \[1, 2, 3], False)

\>>>L1=L2

\>>>L2\[0]=4

\>>>L1, L2, L1 is L2

(\[4, 2, 3], \[4, 2, 3], True)

在上例中，我们首先使L1，L2共享引用列表对象\[1, 2, 3]，然后对L1赋值4。此时，L1引用了新的值为4的整型变量，y依然引用原有列表对象\[1, 2, 3]。之后，我们使L1重新引用列表对象，这时L1和L2再次构成了共享引用。之后，我们对变量L2的第0个位置的元素赋值为4。这是，L1和L2依然引用同一个列表对象，不同的是此列表对象的第0个位置的元素值发生了改变，从1变为4。这种改变影响到了所有引用此列表的变量。之所以出现这种情况，是因为列表对象支持在原位置改变，而整数对象则不支持。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://johannesliu.gitbook.io/data-science-python-implemented/3.0-basic_data_structure/3.5-dynamics.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
