Chapter 3 基本语法与基本数据类型

3.1 说明

本讲很多内容都是在 python 交互式环境下进行的,如果你想在本地运行,可以在命令行输入 python 进入交互式环境。比如:

PS C:\Users\user> python
Python 3.10.7 (tags/v3.10.7:6cc6b13, Sep  5 2022, 14:08:36) [MSC v.1933 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
jimzhang@jimzhang ~ % python3
Python 3.10.7 (main, Sep 14 2022, 22:38:23) [Clang 14.0.0 (clang-1400.0.29.102)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 
user@host:~$ python3
Python 3.10.6 (main, Aug 10 2022, 11:40:04) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 

另外,为了方便(或者夸张地)解释一些问题,本讲 meme 浓度极高!如果大家不喜欢 meme 的话,Jim 在这里跟大家说一句抱歉!

3.2 格式规范

First thing first,在学习 Python 编程之前,一定要养成一种编程习惯,最重要的习惯就是代码格式规范。代码格式的规范性会影响到代码的可读性,所以我们需要遵循一定的规范。这里推荐使用 PEP 8 - Style Guide for Python Code 这个规范。PEP 8 是由 Python 之父 Guido van Rossum 发起的,用于规范 Python 代码的格式。这个规范是 Python 社区的共识,所以我们也需要遵循这个规范。

虽然由于对于 Python 语言的不了解,你很有可能看不懂这个规范,但是你可以先大致了解一下有这么样的规范存在,然后在写代码的时候,请反复查阅这个规范并尽量遵循它。

不遵守 PEP 8 的 Python 开发者不是好的开发者
不遵守 PEP 8 的 Python 开发者不是好的开发者

对了,我很厌恶不遵守 PEP 8 的人,不遵守 PEP 8 的代码真是让人看着就恼火啊!

3.3 基本语法

3.3.1 变量

变量名必须是大小写英文、数字和 _ 的组合,且不能用数字开头。

>>> variable = 1
>>> variable1 = 'This is variable1'
>>> _variable = [1, 2, 3]
>>> PI = 3.1415926 # 大家的共识是常量名用全大写字母

刚才的注释中提到了常量,这里我们先简单介绍一下常量。常量是指在程序运行过程中不会改变的量,在很多其他语言都有常量的概念,比如:

// JavaScript
const PI = 3.1415926;
// C
const double PI = 3.1415926;
Python 里没有常量这个东西
Python 里没有常量这个东西

但是在 Python 中,没有常量的概念,所以我们只能通过一种约定的方式来表示常量,即变量名全部大写。这种约定的方式在 Python 中是很常见的,比如 PIEINFNAN 等等。

3.3.2 注释

不论是什么语言,都一定要写注释!在论文撰写完成投稿时,如果你的 supplement material 中没有注释,那么论文拒稿概率就会提高。原因也很简单,如果没有注释,那么你的代码就会变得难以阅读,别人也很难看懂你的代码。(甚至自己会看不懂自己的代码 XD)

经典,自己看不懂自己上一周写的代码
经典,自己看不懂自己上一周写的代码

Python 中的注释有两种,一种是单行注释,一种是多行注释。

单行注释以 # 开头,多行注释以 '''""" 开头,以 '''""" 结尾。

# 这是单行注释
'''
这是多行注释
这是多行注释
这是多行注释
'''

3.3.3 缩进

不同于其他语言, (这里不能这么讲) Python 中的缩进是通过空格或 tab 实现的。缩进的空格数目没有限制,但是要保持一致。

if True:
    print('True')
else:
    print('False')

3.3.4 分号与逗号

Python 中的分号 ; 与逗号 , 与 C 语言等语言中的用法完全不同,举个例子:

>>> a = 1; b = 2; c = 3
>>> a, b, c = 1, 2, 3; print(a, b, c)
1 2 3

3.3.5 换行

这里的换行准确来说应该叫续行。Python 中的换行是通过 \ 实现的。

>>> a = 1 + 2 + 3 + \
...     4 + 5 + 6 + \
...     7 + 8 + 9
>>> a
45

3.3.6 导入 package

这一节请参考 Geeks for Geeks 上的一篇文章:What is the difference between Python’s Module, Package and Library?

在上一讲中我们只介绍了 package 怎么下载,但是我们并没有介绍怎么使用 package。这一讲我们就来介绍一下 package 怎么使用。

在 Python 中,我们可以使用 import 语句来导入 package。比如我们要导入 math 这个 package,我们可以这样做:

import math

这样我们就可以使用 math 这个 package 中的所有函数了。比如我们要计算 e2 次方,我们可以这样做:

import math
print(math.exp(2))

这里 math.exp 就是 math 这个 package 中的一个函数,它的作用是计算 ex 次方。

我们也可以使用 from 语句来导入 package 中的某个函数。比如我们只想使用 math 这个 package 中的 exp 函数,我们可以这样做:

from math import exp
print(exp(2))

对于一些名字比较长的 package(很多时候其实是约定俗成),我们可以使用 as 语句来给它起一个别名。

import numpy as np

这样我们就可以使用 np 来代替 numpy 了。

以下内容违反 PEP 8!!!!!

在导入 package 的时候,逗号的正确使用可以让我们导入多个函数(或者 package)并且节省代码行数。

from math import exp, log, sqrt
import numpy as np, pandas as pd, matplotlib.pyplot as plt

最后,欢迎大家在交互式环境中尝试一下该语句:

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

3.3.7 保留字

Python 中的保留字是指在 Python 中已经被使用的关键字,不能用作变量名、函数名、类名等。

>>> import keyword
>>> keyword.kwlist
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

上述 keyword.kwlist 就是 Python 中的保留字列表。(后面我们会讲什么是列表)

3.3.8 异常

在 Python 中,异常是指程序在运行过程中出现的错误,比如除数为 0、缩进错误、变量未定义等等。

>>> 1 / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> if True:
... print('True')
  File "<stdin>", line 2
    print('True')
        ^
IndentationError: expected an indented block after 'if' statement on line 1
>>> # 如果是较早版本的 Python 的话是 IndentationError: expected an indented block
>>> print(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

对于异常不要慌,需要精准定位异常的位置,然后根据异常的类型进行修复。(这里想一想怎么说?)

3.4 基本数据类型及其基本操作

整数、复数、浮点数、布尔值、None、字符串、列表、元组、字典、集合

type() 函数可以用来查看变量的类型。示例如下:

>>> a = 1
>>> type(a)
<class 'int'>
>>> b = 1.0
>>> type(b)
<class 'float'>
>>> c = 1 + 2j
>>> type(c)
<class 'complex'>

这里等号就是赋值运算符,a = 1 就是把 1 赋值给变量 a。

3.4.1 整数

整数是没有小数部分的数字,可以是正数、负数或零。

>>> a = 1

一般来说,整数的运算符有 +-*///%**

>>> 5 + 3
8
>>> 5 - 3
2
>>> 5 * 3
15
>>> 5 / 3  # 除法
1.6666666666666667
>>> 5 // 3 # 整除
1
>>> 5 % 3  # 取余
2
>>> 5 ** 3 # 乘方
125

另外,我们也可以对整数进行位运算,位运算符有 &|^~<<>>

>>> 5 & 3  # 与
1 # 00000101 & 00000011 = 00000001
>>> 5 | 3  # 或
7 # 00000101 | 00000011 = 00000111
>>> 5 ^ 3  # 异或
6 # 00000101 ^ 00000011 = 00000110
>>> ~5     # 取反
-6 # ~00000101 = 11111010 + 1 = 11111011
>>> 5 << 3 # 左移
40 # 00000101 << 3 = 00101000
>>> 5 >> 3 # 右移
0 # 00000101 >> 3 = 00000000

3.4.2 复数

复数由实数部分和虚数部分构成,可以用 a + bj 或 complex(a, b) 表示,复数的实部a和虚部b都是浮点型。

>>> a = 1 + 2j
>>> b = complex(1, 2)
>>> b
(1+2j)

复数的运算符有 +-*/

>>> a + b
(2+4j)
>>> a - b
(0+0j)
>>> a * b
(-3+4j)
>>> a / b
(1+0j)

3.4.3 浮点数

浮点数由整数部分与小数部分构成,浮点数运算可能会有四舍五入的误差。

>>> a = 1.1

浮点数的运算符有 +-*/

>>> 1.1 + 2.2
3.3000000000000003
>>> 1.1 - 2.2
-1.1
>>> 1.1 * 2.2
2.4200000000000004
>>> 1.1 / 2.2
0.5

1.1 + 2.2 竟然不是 3.3,这是因为计算机内部表示浮点数时,采用的是二进制浮点数,而二进制浮点数的表示方法并不是十进制小数的表示方法,所以会出现这种情况。

不如我们先借用一下之后课程所需要的判断操作符来判断一下是否是这样(下方代码引入了判断运算符 == 和布尔值,这个我们马上就会提到):

>>> a = 1.1 + 2.2
>>> a == 3.3
False

那我们怎么解决呢?在实际科学研究中,我们通常会使用设定 tolerance 来判断两个浮点数是否相等,即:

>>> a = 1.1 + 2.2
>>> abs(a - 3.3) < 1e-10
True

大家可能注意到了,这里的 abs() 函数是求绝对值的函数,1e-10 是科学计数法,

3.4.4 布尔值

布尔值得名于英国数学家和逻辑学家乔治·布尔(George Boole),他是第一个研究代数逻辑的数学家,他的逻辑学被称为布尔代数。

布尔值只有 TrueFalse 两种值,要么是 True,要么是 False,在 Python中,可以直接用 TrueFalse 表示布尔值(请注意大小写),也可以通过布尔运算计算出来。

>>> a = True
>>> b = False

说起布尔值,就一定要说到比较运算符和逻辑运算符。

3.4.4.1 比较运算符

比较运算符用于比较两个值的大小,比较运算符有 ><>=<===!=

>>> 1 > 2
False
>>> 1 < 2
True
>>> 1 >= 2 # 大于等于
False
>>> 1 <= 2 # 小于等于
True
>>> 1 == 2 # 等于
False
>>> 1 != 2 # 不等于
True

3.4.4.2 逻辑运算符

逻辑运算符用于连接多个比较运算符,逻辑运算符有 andornot

>>> 1 > 2 and 1 < 2
False
>>> 1 > 2 or 1 < 2
True
>>> not 1 > 2
True

现在我们这里引入括号来看一个很有趣的问题。括号的作用和在数学中一样,用来改变运算的优先级。这样的话我们来看一些有意思的问题:

>>> 1 > 2 or 1 < 2
True
>>> 1 > (2 or 1) < 2
False

注意,a or b 的值的确定方法是:如果 a 的值为 True,则 a or b 的值为 a,否则 a or b 的值为 b。所以 2 or 1 的值为 2,所以接下来问题就变成了 1 > 2 < 2,这个问题的答案是 False

False 在数值上等于 0True 在数值上等于 1

>>> 1 > (2 or 1) < 2
False
>>> 1 > 2 < 2
False
>>> False < 2

3.4.5 None

None是Python里一个特殊的类型,用来表示什么都没有,它只有一个值,就是None。

>>> a = None

3.4.6 字符串

从字符串开始,我们将会引入两个新的概念——属性和方法。

字符串是以单引号或双引号括起来的任意文本,比如 'abc'"xyz" 等等。

>>> a = 'abc'
>>> b = "xyz"

3.4.7 列表

列表是一种有序的集合,可以随时添加和删除其中的元素。

>>> a = [1, 2, 3]

3.4.8 元组

元组是另一种有序的列表,但是元组一旦初始化就不能修改。

>>> a = (1, 2, 3)

3.4.9 字典

字典是一种无序的集合,使用键-值(key-value)存储,具有极快的查找速度。

>>> a = {'a': 1, 'b': 2, 'c': 3}

3.4.10 集合

集合是一种无序的不重复元素序列。

>>> a = {1, 2, 3}

3.5 安装 package

3.6 运行一个 python 文件

write something…

3.7 思考题与作业