<-

Hands on Python

Background

Python 作为一个高级编程语言 (high-level language),它的主要工作是将用户编写的 Python 源代码解释成机器能理解的成字节码 (bytecode),以便让机器执行指令。

相比于机器语言和汇编语言等低级语言 (low-level language),使用高级编程语言编写代码有一些好处:代码更少也更易读,编写代码所需的时间更短;更容易做到跨平台运行。

Python 很重要的一个组件是 Python Interpreter。解释器的主要工作是解释并运行 Python: 读取用户编写的 Python 源代码;对源代码进行词法分析,将代码分解成词法单元(tokens);之后进行语法分析,构建抽象语法树(Abstract Syntax Tree,AST)来表示代码的结构;接着将抽象语法树编译成 bytecode,这是一种中间形式的代码;最后,Python 解释器会逐行执行字节码指令,将其转换为机器码并执行,实现源代码的功能。

执行 Python 有两种模式:immediate mode & script mode. 前者是在 terminal 界面进入 Python 解释器的窗口进行即时交互;第二种是通过编写扩展名为 py 的 Python 脚本,使用 Python 解释器去执行该脚本。

在日常调试和数据分析过程中,另一个常用的 python 交互方式是 Jupiter Notebook

Installation

根据操作系统不同,安装 Python 的方式有很多,详情可以参考 Downlaod Python。笔者推荐使用 Anaconda 作为 Python 的环境管理工具。

检验 Python 环境配置是否已经完成:

python --version

Data Type

Python 中常见的数据类型包括:

  1. 整数(int):表示整数值,如 5、-3;
  2. 浮点数(float):表示带有小数点的数值,如 3.14、-0.001;
  3. 字符串(str):表示文本数据,如 ‘hello’、”world”;
  4. 布尔值(bool):表示逻辑值,只有两个取值:True 和 False;
  5. 列表(list):有序、可变的集合,如 [1, 2, 3];
  6. 元组(tuple):有序、不可变的集合,如 (1, 2, 3);
  7. 集合(set):无序、不重复的集合,如 {1, 2, 3};
  8. 字典(dict):无序的键值对集合,如 {‘name’: ‘Alice’, ‘age’: 30}。

Script Structure

在生产级别的 Python 编程中,一个 Python 脚本通常由以下部分构成:

1. 导入模块

在开头导入代码所需的模块,以扩展 Python 的功能和复用代码。例如:

import os
import sys
from datetime import datetime

注:你可以在 Python 标准库, PyPI (Python Package Index), Awesome Python 找到丰富的 Python 库及其功能详情;也可以使用 help(function_name) 可以查看已导入方法内置的说明。

2. 全局变量和常量定义

定义全局变量和常量,用于在整个脚本中共享数据。例如:

MAX_RETRIES = 3
DEBUG_MODE = True

3. 函数和类定义

编写函数和类来组织代码逻辑和实现功能。函数用于封装可重复使用的代码块,类用于组织相关属性和方法。例如:

def calculate_area(radius):
    return 3.14 * radius ** 2

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

注:其中 __init__ 是 Python 中的构造函数,用于在创建对象时初始化对象的属性。

4. 主程序逻辑

编写主要的程序逻辑,包括流程控制、数据处理、调用函数等。这部分代码通常位于脚本的最顶层,用于实现脚本的主要功能。例如:

if __name__ == "__main__":
    radius = 5
    area = calculate_area(radius)
    print(f"The area of the circle is: {area}")

注:if __name__ == "__main__" 被用来判断当前脚本是否作为主程序运行,加上这段代码可以防止在被其他脚本导入时执行了不必要的代码;当 Python 解释器运行一个脚本时,__name__ 变量会被设置为 "__main__",而如果该脚本被作为模块导入到其他脚本时,__name__ 变量会被设置为模块的名称。

5. 异常处理

添加适当的异常处理机制,以处理可能出现的错误和异常情况,确保程序的稳定性和可靠性。例如:

try:
    result = 10 / 0
except ZeroDivisionError as e:
    print("Error: Division by zero!")

注:可以通过 Python 异常文档 查看完整的 Exception 列表,也可以通过 help(ExceptionNameError) 查看特定异常的详细信息。

6. 日志记录

使用日志记录模块记录程序运行时的信息、警告和错误,以便进行故障排查和监控。例如:

import logging
logging.basicConfig(filename='app.log', level=logging.INFO)
logging.info('Program started')

Useful Libraries

1. pdb —— The Python Debugger

pdb 是一个 python 中用于调试代码的模块,它的用法有两种,在代码行中插入:

import pdb; pdb.set_trace()

或者使用 python3.7 之后内置的 breakpoint()

Example: Debug Guessing Number

random.randint(a, b) 返回一个 a <= N <= b 的随机整型,用 Python 执行下面的脚本得不到我们想要的结果。使用 breakpoint() 来寻找原因。

# import pdb
from random import randint

# pdb.set_trace()
breakpoint()
answer = randint(0, 1)
n = input("Guess: 0 or 1?")
if n == answer:
    breakpoint()
    print("Correct!")
else:
    breakpoint()
    print(f"Incorrect. The answer was {answer}.")
-> answer = randint(0, 1)
(Pdb) n
-> n = input("Guess: 0 or 1?")
(Pdb) !answer
1
(Pdb) n
Guess: 0 or 1?1
-> if n == answer:
(Pdb) continue
-> print(f"Incorrect. The answer was {answer}.")
(Pdb) !(n == answer)
False
(Pdb) !type(n)
<class 'str'>
(Pdb) !type(answer)
<class 'int'>
(Pdb) continue
Incorrect. The answer was 1.

通过 debug 发现,比较时变量 n 和变量 answer 类型不同,将第 7 行代码按如下调整即可修复功能:

n = int(input("Guess: 0 or 1?"))

在 debug 模式下,键入 help 查看可以使用的所有命令,以下是开发中最常用的命令及其说明:

| pdb Command   | Action                                           |
| n or next     | Run the next line of code                        |
| s or step     | Step into current line(usually a function call)  |
| r or return   | Return from the current function                 |
| l or list     | List the surrounding code lines                  |
| interact      | Starts an interactive Python interpreter         |
| c or continue | Continue running (until next breakpoint or exit) |
| b or break    | Set a breakpoint for a specific line or function |
| !             | Special prefix to say "run this as Python code"  |
| pp            | Pretty-print the value of a Python expression    |

To be continued…