> For the complete documentation index, see [llms.txt](https://hq-1.gitbook.io/python/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hq-1.gitbook.io/python/di-er-zhang-bian-liang-he-jian-dan-shu-ju-lei-xing.md).

# 第二章 变量和简单数据类型

## 概要

本章作者主要介绍了如何在 python 中操作变量，以及两类最基础的数据类型 —— 字符串和数字。下面我们来按顺序梳理一下相关的要点，以及延伸讨论一些有关 python 语言的基础知识。

## 关于变量

### 变量的命名建议

一个准确规范的变量名称有助于你在重读自己代码的时候更快理解（相信我，你会有这个需求的）。每一种编程语言都有它自己的规范风格，对于 python 来说，推荐你去快速浏览一下[这个页面的“命名”章节](https://zh-google-styleguide.readthedocs.io/en/latest/google-python-styleguide/python_style_rules/#id16)。

### 我是谁，我是不是谁，我在哪里

`a = 1` 是一行最最简单的 python 代码。但当你按下回车之后，python 解释器内部其实发生了很多事情。对于这些事情，我们可以提出哲学三问：

```
>>> a = 1
>>> b = '1'

# 我是谁
>>> type(a)
<class 'int'>
>>> type(b)
<class 'str'>

# 我是不是谁
>>> isinstance(a, int)
True
>>> isinstance(b, int)
False

# 我在哪里
>>> id(a)
4448371840
>>> id(b)
4451721776
```

我们来简单解释一下上面用到的三个 python 内置函数

* `type()` 告诉你某一个**变量**对应的**具体对象（object）**&#x662F;哪一个**类（class）**&#x7684;**实例（instance）**。
* `isinstance()` 告诉你某一个变量它是不是某一个类的实例。
* `id()` 告诉你这个变量所对应的具体对象（object）的**内存位置**。

### 为什么要知道这些呢？

让我们再重复一遍上面这句拗口的话：

> 某一个**变量**对应的**具体对象（object）**&#x662F;哪一个**类（class）**&#x7684;**实例（instance）**

这句话信息量其实很大，从这里我们可以引申出关于 python 的几个重要事实：

* **Python 中的一切都是对象（object）**。
* **Python 中的变量只是一个指针（pointer），或者说一个“名字”，它指向一个存放在内存中的具体对象。**
* **对象是类的实例**。

{% hint style="info" %}
那么什么是类？什么是对象？打个比方，类就是某一种类东西的定义，比如鸭子；而对象就是这个类的一个具体实例，比如唐老鸭和可达鸭就是具体的某只鸭子。**类是对象的模板。**
{% endhint %}

如果说牛顿三大定律构成了牛顿力学，那么**以上三条信息就构成了运行中的 python 世界**。当你运行一行简单的赋值代码如 `x = 2337` 时，实际上发生了下面这些事情：

1. python 在**内存的某个位置（id() 告诉你的那串数字）**&#x521B;建了一个对象，他的类型是 int。
2. python 设定这个 int 对象的值为 2337
3. python 又创建了一个叫做 `x` 的变量名
4. python 把 `x` 指向 1 中创建的那个 int 对象，那个 int 对象的 reference count 从 0 变为 1 （意思是有一个名字指向它，这个概念在内存回收中用到，对初学者不重要）。
5. 从此你可以用 `x` 这个变量名来获得 1 中创建的那个 int 对象

![图中等同于 x = 2337 这行代码](/files/-M6kxIQoUszUZ2O7dmEq)

我认为以上提到的这三条，是 python 知识体系中的主干，你将会看到的很多细枝末节的知识，都是从这些主干生长出来的。或许你仍然不太理解类和对象，继续看下去，我们将会在后面的很多章节反复深化这些东西的内涵。

## 一点点剧透：类与对象

本书的第九章会简单介绍类，而计算机专业课程中，更是有一门叫做面向对象编程（object oriented programming）的课程详细介绍类与对象的知识。但不要害怕，我们并不需要对这些掌握得面面俱到，在这里，我只想告诉你一些当前你所需要知道的关于类和对象的基础知识。

### 类/对象有属性（attribute）和方法（method）

```python
# 这里我给出定义一个鸭子类的完整代码，但是具体的语法解释在第九章，现在可以先不用细看
# 这里的重点是告诉你，什么是类的属性和方法
class Duck:
    def __init__(self, weight, color):
        # 鸭子的一些属性
        self.weight = weight
        self.color = color
    
    # 定义鸭子的一些方法
    def swim(lf):
        print('OK, swimming...')
    
    def fly(self):
        print("No I can't...")
    
    def introduce_myself(self):
        # 可以看到，鸭子的方法可以调用它自己的属性
        print(f'I am a {type(self)} with {self.color} color.')


# 实例化鸭子这个类，生成一个具体的鸭子对象
>>> duck_object = Duck(weight=1, color='yellow')

# 鸭子对象是鸭子的实例
>>> type(duck_object)
<class '__main__.Duck'>
>>> isinstance(duck_object, Duck)
True

# 调用鸭子的属性
>>> duck_object.weight
1
>>> duck_object.color
'yellow'

# 调用鸭子的方法，也就是让它完成一些事情
>>> duck_object.swim()
OK, swimming...
>>> duck_object.fly()
No I can't...
>>> duck_object.introduce_myself()
I am a <class '__main__.Duck'> with yellow color.

```

用上面的鸭子类来作为例子

* 属性就是一些固定的值，比如鸭子的体重（对应一个数字类型的变量）；鸭子的羽毛颜色（对应一个字符串，如 ‘yellow’）
* 方法就是一个能够被调用的函数，完成特定的事情，方法如同函数一样可以接受参数，方法内部可以使用属性

### 重新认识字符串

```
# 我把一个字符串对象赋值给变量 a，a 指向的是这个字符串对象，
# 字符串对象具有字符串类的全部属性和方法
>>> a = 'this two shall pass'

# 字符串对象是字符串类的实例
>>> type(a)
<class 'str'>

# 本章中提到的所有操作，其实都是在调用字符串对象的方法，这些方法都由字符串类这个模板定义
# 当你做这些操作时，你在调用字符串类的方法
# 这些方法帮你完成一些复杂的任务，没有他们的话，你需要写很多代码来实现同样的结果
>>> a.split(' ')
['this', 'two', 'shall', 'pass']
>>> a.upper()
'THIS TWO SHALL PASS'
>>> a.title()
'This Two Shall Pass'

# 当我定义一个数字类的时候， 它就具有不一样的属性和方法
>>> b = 42
# 数字类不存在 upper() 方法，因此我看到了一个 AttributeError
>>> b.upper()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute 'upper'

```

书中作者告诉了你很多关于字符串的操作方法（大小写，去除空白等等），**本质上，他只是挑选了字符串这个类的众多方法中，最常见和重要的几个**。而属于字符串类的方法和知识[还有很多很多](https://www.runoob.com/python3/python3-string.html)。你不妨浏览一下[这个链接](https://www.runoob.com/python3/python3-string.html)，但不需要一一记住，只要知道，许许多多事情是可以通过一个类的方法快速实现的。

{% hint style="warning" %}
超纲内容

如果你看上面那个链接，你会看到除了字符串方法外，还有很多字符串运算符的知识。比如 “+”，比如通过中括号和索引获得字符串的一部分 `"string"[2:4]。`这些语法似乎不像是类似`string.upper()` 这样的方法调用，但他们其实也是方法！

python 中有一些内置的方法，名称以双下划线包围，一般的初学教程不会提及。但如果使用`dir()` 这个函数，就可以看到所有的内置方法。其中`__add__()` 这个方法就实现了加号运算，有它的存在，你才可以使用加号连接两个字符串。加号只是这个特殊方法的一种简便写法！

```
# dir() 查看一个字符串，排第一的方法'__add__'就是加号的具体实现
>>> dir('')
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
# 更有趣的是，dir() 本身也是在调用这个类的内置 __dir__() 方法才获得了上述信息
```

{% endhint %}

## python 中的一切都是对象

请记住，**一切**。Python 中，哪怕是 None ，都属于一个叫做 NoneType 的类，一样可以实例化并赋值给一个对象。上面的三条是普适的！

```
>>> a = None
>>> type(a)
<class 'NoneType'>
```

### 学习建议：学习 python 的用法就是学习 python 中各种类具有的属性和方法

正因为python 中的一切都是对象，学习某个 python 中的对象，也就成为了学习这个 对象/类 所具有的属性和方法。但是，千万别去死记硬背 string 类有哪些方法，每个方法有什么参数，有什么作用等等。你应该通过**不断的使用它来达到记忆的效果**。那些最常用的方法会自然成为你记得最深的方法。**编程是一个熟练功。**

与此同时，多 google，多看别人的代码，可以偶尔学到一些 **“原来这件事情可以通过这个方法完成”** 这样的知识。于是你就会在下一次遇到相同的问题时，用正确的“方法”去解决。

## 格式化字符串的方法之一：f-string （Bonus）

在编程过程中，你会经常需要把几个变量的值变成一句完整的话 print 出来，你有两种方式来做到这一点：

```
# 假如有关今天的日期信息存在几个不同的变量中，我们希望把这些变量变成一句话
date = '07'
month = 'May'
year = 2020
weekday = 'Thur'

# 方法一，用字符串加法，这是本书中的做法
>>> print('Today is ' + month + ' ' + date + ', '\
 + str(year) + ' ' + weekday + '.')
Today is May 07, 2020 Thur.

# 方法二，用 f-string 来实现字符串格式化
>>> print(f'Today is {month} {date}, {year} {weekday}.')
Today is May 07, 2020 Thur.
```

很显然，使用格式化字符串是更加 pythonic 的方法。而 f-string 是几种格式化字符串方法中最为**优美（程序员们喜欢用的高逼格词汇）**&#x7684;一种。

现在你知道了这个名词，就可以去 google 更多关于 f-string 的用法了。

## 看完之后，你应该能够

* 名词解释：类（class），实例（instance），对象（object）

```
           类
           |
           | （实例化）
           v
名称 --->  对象 （存在于内存中的具体数据，他的结构和行为都符合类的定义）
    (指向）

```

* 理解这些 python 内置函数：type()，isinstance()，id()
* 当你要学习或者搜索 python 中的字符串操作时，你实际在学习？
  * 答：字符串类的方法
* 死记硬背三大定理（以后慢慢理解）：
  * **Python 中的一切都是对象（object）**。
  * **Python 中的变量只是一个指针（pointer），或者说一个“名字”，它指向一个存放在内存中的具体对象。**
  * **对象是类的实例**。

## 拓展阅读

* 关于字符串方法更详细的罗列：<https://www.runoob.com/python3/python3-string.html>
* 关于 python 中指针的讨论：<https://realpython.com/pointers-in-python/>
