【全新第二版《Learn AI-assisted Python Programming》封面】
写在前面
本书前三章负责给大家上开胃菜,第四、五章则进一步介绍了读懂 Copilot 回复的 Python 代码所需了解的基础语法。毕竟 AI 工具目前只能起到辅助编程的作用,主体还在人这边。与其费心钻研怎么写好提示词让 Copilot 等工具一气呵成,还不如主动了解 Python 的基础语法来得实惠。真正能将 AI 编程玩出花样的大神没有一个是纯小白。这些内容也是为后续高级话题的展开做铺垫。具有 Python 基础的朋友可以直接跳过,因为确实乏善可陈,都是入门级的知识点。
Ch04: Reading Python code: Part 1
本章概要
- 为什么理解代码很重要
- 让
Copilot
解释代码- 用函数来分解大型问题
- 使用变量来存值
- 用
if
语句来做决策- 用字符串存储和操作文本
- 用列表来收集和操作多个值
1 开宗明义:为什么要读懂代码
这里的 懂 分两个层面:
- 知道每句代码的具体功能和作用;
- 知道整段代码的目的。
和现实生活中一样,从基层提拔的干部往往更能胜任工作,Copilot
辅助编程更是如此。当提供的程序达不到预期时,与其一味去优化提示词工程直到 Copilot
纠正问题,还不如自己懂点代码,略加修改就能符合要求。
书中给出了读懂代码的三个好处:
- 判定代码的准确性:预先排除存在问题的代码;
- 提高测试效率:提高测试的针对性和有效性;
- 提高
AI
辅助编程的水平:真正擅于利用Cursor
等 AI 辅助编程工具的人,绝大部分是很懂代码的高级程序员,知道大模型提供的代码能干什么,还缺什么,应该怎么完善等。
正因如此,本书接下来的两章将重点介绍 Python
的核心语法,为后续 Copilot
工具的高级用法作铺垫。
2 让 Copilot 解释代码
主要有三种方式:
- 借助右键菜单:选中代码后,从右键菜单选
Copilot
➡️explain
(如图 4.1 所示); - 使用
/explain
指令:如图 4.2 所示; - 自行设计解释提示词:适用于需求较复杂、
Copilot
不能完全理解你的意图的情况。
【图 4.1 利用 VSCode 右键菜单的 Copilot 解释功能】
【图 4.2 实测 Copilot 的 explain 指令解释所选代码段】
关于 Copilot 可能出错的问题
诚然
Copilot
并不完美,无法保证每一次给出的代码都是百分百正确的,但就算自己手动上网查找资料,也不能保证百分百正确。若实在信不过Copilot
给出的回复内容,可以从不同角度多次提问,出错的概率相对更低。
3 Python 基本语法简介(上)
这部分内容非常浅显,主要分五个主题展开:
- 函数
- 变量
- 条件语句
- 字符串
- 列表
这里仅梳理最关键的知识点。
函数的主要作用是拆解问题,每个函数执行特定的代码块,并将处理结果用 return
语句返回(通常由某个变量接收处理结果)。
除了自定义函数,Python
还提供了大量内置函数以及第三方库函数,其调用和传参方式和自定义函数一致。
在 Python
中一个等号代表赋值操作符,两个等号才表示相等。
if
语句用于处理逻辑分支,多种情况用 if
和用 elif
书写效果不尽相同:
- 多个
if
语句在Python
中会依次执行,只要满足条件即可执行对应的代码块; - 多个
elif
组合的语句只是一个独立的if
语句,一旦满足前面某个条件,后续分支将不再执行。
if
分支语句和函数定义一样,都是通过代码缩进来标识代码块的,即便在 REPL
命令行环境也要确保缩进量的一致。
字符串(String
)具有很多内置方法:
>>> 'abc'.isupper()
False
>>> 'Abc'.isupper()
False
>>> 'ABC'.isupper()
True
>>> 'abc'.isdigit()
False
>>> '345bc'.isdigit()
False
>>> '345'.isdigit()
True
>>> 'abc6'.isalnum()
True
>>> 'abc def'.isalnum()
False
>>> 'abcdef#'.isalnum()
False
列表用于操作和管理一组具有某种具体含义和功能的值。列表中的元素值可通过索引(index,从 0 开始计数)来访问。
和字符串一样,列表也有很多内置方法:
>>> books = ['The Invasion', 'The Encounter', 'The Message']
>>> books
['The Invasion', 'The Encounter', 'The Message']
>>> books.append('The Predator')
>>> books
['The Invasion', 'The Encounter', 'The Message', 'The Predator']
>>> books.reverse()
>>> books
['The Predator', 'The Message', 'The Encounter', 'The Invasion']
>>> books[0]
'The Predator'
>>> books[1]
'The Message'
>>> books[2]
'The Encounter'
>>> books[3]
'The Invasion'
>>> books[4]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> books[-1]
'The Invasion'
>>> books[-2]
'The Encounter'
>>> books[1:3]
['The Message', 'The Encounter']
>>> books[:3]
['The Predator', 'The Message', 'The Encounter']
>>> books[1:]
['The Message', 'The Encounter', 'The Invasion']
>>> books
['The Predator', 'The Message', 'The Encounter', 'The Invasion']
>>> books[0] = 'The Android'
>>> books[0]
'The Android'
>>> books[1] = books[1].upper()
>>> books[1]
'THE MESSAGE'
>>> books
['The Android', 'THE MESSAGE', 'The Encounter', 'The Invasion']
但需要注意的是,列表的值是可变的(mutable
),而字符串是不可变的(immutable value
):
>>> title = 'The Invasion'
>>> title[0]
'T'
>>> title[1]
'h'
>>> title[-1]
'n'
>>> title[0] = 't'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
Ch05: Reading Python code: Part 2
本章概要
- 用循环控制代码重复执行的次数
- 用缩进组织 Python 代码
- 建立字典来保存成对关联的值
- 设置文件来读取和处理数据的方法
- 用模块开辟新的工作领域
本章接上一章介绍的 Python 基础,主要从循环、缩进、字典、文件和模块五个方面进一步介绍了 Python 十大基础语法的后半部分。
1 循环
分类:
for
循环:循环次数确定;while
循环:循环次数不确定;
1.1 for 循环
for
循环通过 for-in
结构运行,可作用于字符串:
s = 'vacation'
for char in s:
print('Next letter is', char)
Next letter is v
Next letter is a
Next letter is c
Next letter is a
Next letter is t
Next letter is i
Next letter is o
Next letter is n
也可以作用于列表:
>>> lst = ['cat', 'dog', 'bird', 'fish']
>>> for animal in lst:
... print('Got', animal)
... print('Hello,', animal)
...
Got cat
Hello, cat
Got dog
Hello, dog
Got bird
Hello, bird
Got fish
Hello, fish
此外还能借助索引值遍历列表:
>>> for index in range(0, len(lst)):
... print('Got', lst[index])
... print('Hello,', lst[index])
...
Got cat
Hello, cat
Got dog
Hello, dog
Got bird
Hello, bird
Got fish
Hello, fish
其中 range(start, end)
为 Python
内置方法,用于生成 [start, end)
区间内的索引值序列。range(5)
是 range(0, 5)
的简写形式。
1.2 while 循环
当循环次数不确定时,通常用 while
循环控制具体逻辑:
def get_strong_password():
"""
Keep asking the user for a password until it’s a strong password,
and return that strong password.
"""
password = input("Enter a strong password: ")
while not is_strong_password(password):
password = input("Enter a strong password: ")
return password
其中的 is_strong_password()
函数是第三章演示过的密码强弱判定函数(根据最新版 Copilot
回复):
def is_strong_password(password):
"""
A strong password has at least one uppercase character,
at least one number, and at least one punctuation.
Return True if the password is a strong password, False if not.
"""
has_uppercase = False
has_number = False
has_punctuation = False
for char in password:
if char.isupper():
has_uppercase = True
elif char.isdigit():
has_number = True
elif char in "!@#$%^&*()_+-=[]{}|;:,.<>?":
has_punctuation = True
return has_uppercase and has_number and has_punctuation
只要输入的密码其强度不符合要求,程序就会一直循环,反复提示用户重新输入,直至读到一个强密码。
为防止 while
陷入死循环,也可以人为设置退出条件:
lst = ['cat', 'dog', 'bird', 'fish']
index = 0
while index < len(lst):
print('Got', lst[index])
print('Hello,', lst[index])
index += 1
# 运行结果
Got cat
Hello, cat
Got dog
Hello, dog
Got bird
Hello, bird
Got fish
Hello, fish
2 缩进
必须缩进的语法结构:
if
语句- 函数体
- 循环体
例如:
hour = int(input('Please enter the current hour from 0 to 23: '))
if hour < 12:
print('Good morning!')
print('Have a nice day.')
elif hour < 18:
print('Good afternoon!')
else:
print('Good evening!')
print('Have a good night.')
def larger(num1, num2):
if num1 > num2:
return num1
else:
return num2
lst = ['cat', 'dog', 'bird', 'fish']
index = 0
while index < len(lst):
print('Got', lst[index])
print('Hello,', lst[index])
index += 1
上述结果通过相互嵌套,还能形成更复杂的业务逻辑:
def num_points(word):
"""
Each letter is worth the following points:
a, e, i, o, u, l, n, s, t, r: 1 point
d, g: 2 points
b, c, m, p: 3 points
f, h, v, w, y: 4 points
k: 5 points
j, x: 8 points
q, z: 10 points
word is a word consisting of lowercase characters.
Return the sum of points for each letter in word.
"""
points = 0
for char in word: # 函数内的缩进
if char in "aeioulnstr": # for 循环内的缩进
points += 1 # if 语句内的缩进
elif char in "dg":
points += 2
elif char in "bcmp":
points += 3
elif char in "fhvwy":
points += 4
elif char == "k":
points += 5
elif char in "jx":
points += 8
elif char in "qz":
points += 10
return points
出于可读性考虑的缩进
有些结构不必缩进,但为了美观和方便阅读,也会引入缩进。常见的有长内容行的换行缩进、大段字典声明中的换行缩进等。
例如:
def is_strong_password(password): """ A strong password has at least one uppercase character, at least one number, and at least one punctuation. Return True if the password is a strong password, False if not. """ return any(char.isupper() for char in password) and \ # 行尾的反斜杠表示续行 any(char.isdigit() for char in password) and \ # 此处缩进不作要求,仅方便阅读 any(char in string.punctuation for char in password)
再如:
def num_points(word): """ Each letter is worth the following points: a, e, i, o, u, l, n, s, t, r: 1 point d, g: 2 points b, c, m, p: 3 points f, h, v, w, y: 4 points k: 5 points j, x: 8 points q, z: 10 points word is a word consisting of lowercase characters. Return the sum of points for each letter in word. """ points = {'a': 1, 'e': 1, 'i': 1, 'o': 1, 'u': 1, 'l': 1, # 字典天然支持多行输入 'n': 1, 's': 1, 't': 1, 'r': 1, # 此处缩进不作要求,仅提高可读性 'd': 2, 'g': 2, 'b': 3, 'c': 3, 'm': 3, 'p': 3, 'f': 4, 'h': 4, 'v': 4, 'w': 4, 'y': 4, 'k': 5, 'j': 8, 'x': 8, 'q': 10, 'z': 10} return sum(points[char] for char in word)
2.1 循环嵌套中的多级缩进
countries = ['Canada', 'USA', 'Japan']
for country1 in countries:
for country2 in countries: # 外层循环所需缩进
print(country1, country2) # 内层循环所需缩进
# 运行结果:
Canada Canada
Canada USA
Canada Japan
USA Canada
USA USA
USA Japan
Japan Canada
Japan USA
Japan Japan
2.2 二维列表的遍历
利用 range
和循环嵌套,还能实现二维列表的遍历:
medals = [[2, 0, 2],
[1, 2, 0],
[1, 1, 0],
[0, 1, 0],
[1, 0, 0]]
for i in range(len(medals)):
for j in range(len(medals[i])):
print(i, j, medals[i][j])
# 运行结果:
0 0 2
0 1 0
0 2 2
1 0 1
1 1 2
1 2 0
2 0 1
2 1 1
2 2 0
3 0 0
3 1 1
3 2 0
4 0 1
4 1 0
4 2 0
可见,只有内层循环结束后,外层循环才会开始下一个新值的迭代。
3 字典
字典与列表同样都是可变更值的数据类型,其写法类似 JavaScript
中的对象和 JSON
。字典自带两个遍历方法:
freq = {'DNA': 11, 'acquire': 11, 'Taxxon': 13, \
'Controller': 20, 'morph': 41}
freq.keys()
freq.values()
实测结果:
字典的删除用 freq.pop(key)
完成(务必注意大小写):
>>> freq.pop('Controller')
20
>>> freq
{'DNA': 11, 'acquire': 11, 'Taxxon': 13, 'morph': 41}
字典也可参数 for-in
遍历:
>>> for word in freq:
... print('Word', word, 'has frequency', freq[word])
...
Word DNA has frequency 11
Word acquire has frequency 11
Word Taxxon has frequency 13
Word morph has frequency 6
4 文件操作
两种方式:
nfl_file = open('nfl_offensive_stats.csv')
with open('nfl_offensive_stats.csv', 'r') as f:
(推荐)
第一种写法需要手动关闭文件;第二种会自动关闭。
5 模块
常见的 Python
模块如下:
模块 | 内置模块 | 描述 |
---|---|---|
csv | 是 | 帮助读写和分析 CSV 格式文件 |
zipfile | 是 | 帮助创建和解压 zip 格式文件 |
matplotlib | 否 | 用于绘图的图形模块,可作为其他图形库的基础,并提供高级定制功能 |
plotly | 否 | 用于创建交互式网络图形的绘图模块 |
seaborn | 否 | 建立在 matplotlib 模块基础上的图形模块,较之 matplotlib 更容易创建高质量的图形 |
pandas | 否 | 数据处理模块,专门处理与电子表格类似的数据帧(data frame ) |
scikit-learn | 否 | 包含机器学习(从数据中学习并进行预测)的基础工具模块 |
numpy | 否 | 提供高效数据处理的工具模块 |
pygame | 否 | 游戏编程模块,可用 Python 构建交互式图形类游戏 |
django | 否 | 有助于设计网站及 Web 应用的网络开发模块 |
内置模块需 import
引入后使用;其他模块则需要先安装再导入使用。
借助模块可简化文件读写操作:
>>> import zipfile
>>> zf = zipfile.ZipFile('my_stuff.zip', 'w', zipfile.ZIP_DEFLATED)
>>> zf.write('nfl_offensive_stats.csv')
>>> zf.write('actors.csv')
>>> zf.write('chores.csv')
>>> zf.close()
再如:
def create_zip_file(file_name):
"""
Add all of the csv files in the current directory to a zip file named file_name.
If file_name already exists, it will be overwritten. Not included the csv files in the subdirectories.
The zip file will be created in the current directory.
Args:
file_name (str): the name of the zip file to create.
"""
import os
import zipfile
# Get the list of all files in the current directory
files = os.listdir('.')
# Create a zip file with the specified name
with zipfile.ZipFile(file_name, 'w') as zipf:
for file in files:
# Check if the file is a CSV file
if file.endswith('.csv'):
# Add the CSV file to the zip file
zipf.write(file)
print(f'Added {file} to {file_name}')
print(f'Created {file_name} with all CSV files in the current directory.')
create_zip_file('my_stuff.zip')