这是我当初最希望有人递给我的速成教程:只讲你真会用到的东西、真会碰到的错误,也允许你暂时跳过其余内容。直接读,或者在任一章节点“播放”,泡咖啡时也能学。
🎙️ 发布并录制于: · 更新于 ·
左边写名字,右边放值,就这么简单。不用声明类型,也不用分号。类型提示现在也可以先跳过,等以后遇到时,自然就能看懂它为什么有用。
name = "Ada" # 字符串
age = 36 # 整数
height = 1.7 # 浮点数
is_ready = True # T 必须大写,写成 true 会报错
nothing = None # Python 里的“null”,N 必须大写
print(name, age) # Ada 36NameError: name 'true' is not definedTrue 和 False,不是 true 和 false。如果你从 JavaScript 转过来,这周大概会顺手写错三次。Python 有三种字符串格式化方式,其中两种先不用学。百分号格式化和 .format() 常见于旧教程、旧项目;你只需要会写 f-string:引号前加字母 f,变量放进花括号。
name = "Ada"
msgs = 5
print(f"Hi {name}, you have {msgs} messages")
# 这四个方法足以覆盖九成实际字符串处理:
s = " Swift Grasp "
s.strip() # "Swift Grasp",去掉首尾空白
s.lower() # 用于忽略大小写的比较
s.split() # ['Swift', 'Grasp']
", ".join(["a", "b"]) # "a, b",没错,join 写在分隔符上TypeError: can only concatenate str (not "int") to str"age: " + 36。Python 不肯直接把文本和数字粘起来。别到处塞 str(),改用 f-string:f"age: {36}",问题以后就不会再来。这里没有花括号。冒号表示代码块开始,而缩进本身就是语法。这是新手第一天最常见的报错来源,所以现在就把它处理干净。
score = 87
if score >= 90:
print("A")
elif score >= 80:
print("B") # 会执行这一行
else:
print("keep going")
# and / or / not 是单词,不是 && || !
if 80 <= score < 90: # 链式比较,很有 Python 风格
print("solid B")
label = "pass" if score >= 60 else "fail"IndentationError: unexpected indent,或者它的邪恶双胞胎:TabError: inconsistent use of tabs and spaces这是每天都会用的容器:有顺序、能混装不同类型、需要时还能增长。先抓住两个重点:负数索引从末尾往前数,切片用来截取一段范围。
langs = ["python", "js", "rust"]
langs.append("go") # 添加到末尾
langs[0] # "python"
langs[-1] # "go",最后一项,不必绕去算 len()
langs[1:3] # ['js', 'rust'],不包含结束索引
len(langs) # 4
"rust" in langs # True
nums = [3, 1, 2]
sorted(nums) # 返回排序后的新副本:[1, 2, 3]
nums.sort() # 原地排序,返回 NoneIndexError: list index out of rangelangs[4] 已经越界。想拿最后一项时,直接用 langs[-1],不要写 langs[len(langs)-1];后一种写法最容易滋生这类错误。字典保存键值对,很像 JSON 对象。我估计实际写 Python 时,有一半时间都在传递字典。尽早养成一个习惯:某个键必须存在时用方括号;它可能不存在时用 .get()。
user = {"name": "Ada", "age": 36}
user["name"] # "Ada"
user["role"] = "admin" # 新增或覆盖
user.get("email") # None,不会报错
user.get("email", "n/a") # "n/a",提供默认值
for key, value in user.items():
print(f"{key} = {value}")KeyError: 'email'.get() 会稳妥得多。Python 的 for 会直接遍历每一项。如果你正在写 for i in range(len(things)),先停一下,几乎总有更干净的写法。还需要索引?那就用 enumerate。
for lang in ["python", "js", "rust"]:
print(lang)
for i, lang in enumerate(["a", "b"]):
print(i, lang) # 先输出 0 a,再输出 1 b
for i in range(3): # 只有数字:0, 1, 2
print(i)
count = 3
while count > 0:
count -= 1 # Python 没有 count--for x in items[:];或者用下一节的推导式创建新列表。用 def 定义函数,用 return 交回结果。默认值让参数变成可选项;调用时写出参数名,比如 greet(excited=True),半年后回头看依然清楚。
def greet(name, excited=False):
msg = f"Hello, {name}"
return msg + "!" if excited else msg
greet("Ada") # Hello, Ada
greet("Ada", excited=True) # Hello, Ada!
# 返回两个值,实际是一个元组,接收时解包
def min_max(nums):
return min(nums), max(nums)
lo, hi = min_max([3, 1, 9]) # lo=1, hi=9def add(item, items=[])。这个默认列表只创建一次,之后所有调用共享它;第一次调用加入的内容,会出现在第二次调用里。每个 Python 开发者大概都会中招一次。请改用 items=None,再在函数内部写 if items is None: items = []。一行创建新列表:左边做转换,中间写循环,右边加筛选。我只有一条实在的规矩:如果需要不止一个 if,或者还要嵌套循环,就老老实实写普通循环。卖弄聪明的一行代码,很容易让你白丢一个下午。
nums = [1, 2, 3, 4, 5]
squares = [n * n for n in nums] # [1, 4, 9, 16, 25]
evens = [n for n in nums if n % 2 == 0] # [2, 4]
# 字典版本
lengths = {w: len(w) for w in ["hi", "hello"]}
# {'hi': 2, 'hello': 5}打开文件一律用 with。即使代码执行到一半报错,它也会替你关闭文件。还要始终传入 encoding="utf-8"。很多教程没写,是因为在作者的 Mac 上碰巧没问题;到了 Windows,默认编码不同,真实文件很快就会给你上一课。
with open("notes.txt", "w", encoding="utf-8") as f:
f.write("line one\n")
with open("notes.txt", encoding="utf-8") as f:
for line in f: # 逐行读取,文件多大都可以
print(line.strip())
# 读写 JSON,每周都会用到
import json
with open("data.json", "w", encoding="utf-8") as f:
json.dump({"name": "Ada"}, f)UnicodeDecodeError: 'charmap' codec can't decode byte 0x9dencoding="utf-8"。解决办法就是养成上面的习惯。多敲这几个字符,比困惑一个小时便宜得多。这里练两项本事。第一,看到 Traceback 时,先读最后一行,那里才是真正的错误;上面的内容只是调用路径。第二,只捕获明确的错误类型。一个光秃秃的 except: 会吞掉代码块里的所有问题,之后你可能要花几小时找它到底吃掉了什么。
try:
age = int("not a number")
except ValueError:
print("that wasn't a number")
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"oops: {e}")
# 输入不合理时主动抛出错误
def set_age(age):
if age < 0:
raise ValueError("age can't be negative")Traceback (most recent call last):,请从下往上读。最后一行说明哪里出错;倒数第二行给出确切文件和行号;更上面则是程序如何走到这里。多数新手从上往下读,很快就会迷失在框架内部。说句实话:就算几周不定义任何类,你照样能写出有用的 Python,所以别卡在这里。先学会读懂类就够了:__init__ 在创建对象时运行,self 就是对象在指代自己。然后继续往前走。等字典变得难以收拾,再回来学。
class Dog:
def __init__(self, name):
self.name = name
self.tricks = []
def learn(self, trick):
self.tricks.append(trick)
return f"{self.name} learned {trick}"
rex = Dog("Rex")
rex.learn("sit")
rex.tricks # ['sit']TypeError: learn() takes 1 positional argument but 2 were givenself。每个实例方法的第一个参数都是 self。Python 会自动把对象传进去,所以在真正理解这一点之前,参数数量总像是差了一位。下面这些写法,每个人都会搜索上百次。把这一节加入书签,它本来就是干这个的。
# 交换两个变量
a, b = b, a
# 反转列表或字符串
nums[::-1]
# 去重并保留顺序,list(set(x)) 会打乱顺序,不要用
list(dict.fromkeys(items))
# 最常见的元素
from collections import Counter
Counter(words).most_common(1)
# 合并两个字典,键冲突时右侧优先
merged = {**defaults, **overrides}
# 读取用户输入
name = input("Name: ")
# 在终端安装软件包或运行脚本
# pip install requests
# python script.py这就是能真正拿来干活的语言核心。想让它留在脑子里,靠的不是继续读,而是挑一件生活中又小又烦的事,比如批量重命名文件,或者写个终端待办清单,然后把它做出来。你现在已经会得够多了。