基于 Learn X in Y minutes 进行修改
注释
# 单行注释: 用井字符开头
# 多行注释: 需要用 3 个双引号或者单引号包裹
"""
多行字符串用三个引号包裹
也常被用来做多行注释
可以是单引号, 也可以是双引号
注意, 必须是英文符号
"""
# 在调试代码时, 经常把某一部分代码注释掉, 来临时跳过某些代码, 进行对比测试
数据类型
# Python的数据类型:
# 整数 int
# 浮点数 float
# 字符串 str
# 布尔值 bool
# 数组 array
# 元组 turple
# 字典 dict
# 集合 set
# 空对象 None
# 用来获取数据类型的函数
type()
# 整数 integer
3 # → 3
type(3) # → <class 'int'>
a = int(input('请输入数字')) # 想要获取输入的数字, 记得要转化一下
# 浮点数 float
1.0 # → 1.0
type(1.0) # → <class 'float'>
# 布尔值 boolean
True # 注意, True 和 False 都必须是首字母大写
False
type(True) # → <class 'bool'>
# 整数也可以当作布尔值
0 and 2 # → 0
-5 or 0 # → -5
0 == False # → True
2 == True # → False
1 == True # → True
# 这些值都算是 False: None、0、空字符串、空列表、空字典
# 而其他的所有的值都是 True
# 注意, 没有所谓空集合, 因为空集合就是空字典 {}
bool(0) # → False
bool("") # → False
bool([]) # → False
bool({}) # → False
# 字符串 string
type("Hello World") # → <class 'str'>
# 字符串用单引号或者双引号都可以
"这是个字符串"
'这也是个字符串'
# 字符串可以被当作列表
"This is a string"[0] # → 'T'
# 列表 list
li = []
type(li) # → <class 'list'>
# 元组 tuple
# 元组是不可改变的序列
tup = (1, 2, 3)
type(tup) # → <class 'tuple'>
tup[0] # → 1
tup[0] = 3 # 抛出TypeError, 因为元组不能被修改
# 字典 dictionary
empty_dict = {}
type(empty_dict) # → <class 'dict'>
# 字典的初始化
filled_dict = {"one": 1, "two": 2, "three": 3}
# 集合 set
empty_set = set()
type(empty_set) # → <class 'set'>
# 初始化一个集合, 和字典的初始化相似
some_set = {1, 1, 2, 2, 3, 4} # some_set现在是{1, 2, 3, 4}
# None是一个对象
None # → None
变量
# 在变量赋值前, 不用提前声明变量
# 变量名用数字、字母、下划线组成, 但是数字不能放在变量名的第1位
# 变量名对大小写敏感, 也就是说 thisName 不等于 thisname
# 建议变量命名使用小写字母, 然后用下划线来分隔
some_var = 5
some_var # → 5
# 变量命名也可以包含数字, 但是数字不能放在命名的第 1 位
4some_var # 报错, SyntaxError: invalid syntax
# 访问未赋值的变量会抛出异常
# 参考教程后面“流程控制:异常”的部分, 来学习异常处理
some_unknown_var # 抛出NameError
# 全局变量
global some_var
操作符
操作符: 算术操作符
“操作符”的英文名是 Operator, 也称为“运算符”, 包括算术运算、比较运算、逻辑运算… 但是, 我建议用“操作符”来指称, 而不要用“运算符”来指称.
这是因为“运算”这个词给我们的心理暗示是数学上的加减乘除运算, 我们直观上不会认为比较操作、逻辑操作是一种运算 ( 尽管对于计算机来说, 的确是运算 ), 因此大脑面对“比较运算”和“逻辑运算”这些词的时候会产生不协调感. 而“操作符”是一种中性的表述, “操作”可以包括算术运算、比较、逻辑判断…
# Python 中的算术和我们在学校学的算数没有太大区别
1 + 1 # → 2
8 - 1 # → 7
10 * 2 # → 20
# “除法”例外, 除法的结果会自动转换成浮点数
35 / 5 # → 7.0
5 / 3 # → 1.6666666666666667
-5 / 3 # → -1.6666666666666667
# 两个斜杠//的叫“整数除法”, 需要向下取整
# 本质是 floor 操作, floor = 地板, 也就是说取接近计算结果最近的那个整数
5 // 3 # → 1
5.0 // 3.0 # → 1.0 # 浮点数也可以进行整数除法
-5 // 3 # → -2 # 注意这里! 记住, 整数除法的结果都是向下取整, 也就是往小的取整
-5.0 // 3.0 # → -2.0
# 如果想要截取除法结果的整数部分, 需要使用 math 模块的 trunc 函数
import math
math.trunc(1 / 2) # → 0
math.trunc(-5 / 3) # → -1
# 浮点数的运算结果也是浮点数
3 * 2.0 # → 6.0
# 取余数, 也叫“取模”、“模除”
7 % 3 # → 1
# x 的 y 次方
2**4 # → 16
3**2 # → 9
# 平方
5**2 # → 25
9**2 # → 81
操作符: 逻辑操作符
# 布尔值
True
False
# 逻辑操作符, 注意 and 和 or 都是小写
True and False # → False
False or True # → True
# 逻辑操作符, 用 not 取非
not True # → False
not False # → True
# 整数也可以当作布尔值
0 and 2 # → 0
-5 or 0 # → -5
0 == False # → True
2 == True # → False
1 == True # → True
操作符: 比较操作符
# 比较大小
1 < 10 # → True
1 > 10 # → False
2 <= 2 # → True
2 >= 2 # → True
# 用 == 判断是否相等
1 == 1 # → True
2 == 1 # → False
3 = 2 # → 会报错, 因为 = 是表示赋值, == 才是判断是否相等
# 用 != 判断是否不等于
1 != 1 # → False
2 != 1 # → True
# 大小比较可以连起来!
1 < 2 < 3 # → True
2 < 3 < 2 # → False
# 当与None进行比较时, 不要用 ==
# 要用 is
# is 是用来比较两个变量是否指向同一个对象
"etc" is None # → False
None is None # → True
操作符: 字符串的操作符
# 用加号连接字符串
"Hello " + "world!" # → "Hello world!"
操作符: 列表的操作符
# 用 + 和空格来拼接列表
[1, 2, 3] + ['hello', 'python'] # → [1, 2, 3, 'hello', 'python']
# 用 * 来拷贝列表
[1, 2, 3]*3 # → [1, 2, 3, 1, 2, 3, 1, 2, 3]
# 列表也有逻辑操作
# ==、!=、<、<=、>、>=、in、not in
# 将两个列表中的元素逐个拿出来比较
# 遵循字符串比较相同的规则 -- 一旦决出胜负, 即刻停止, 不用再比较后面的元素
# in、not in 是用来判断元素是否在列表中的逻辑操作
a_list = [1, 2, 3]
b_list = [8]
c_list = [1, 4, 3]
a_list > b_list # → False
a_list < b_list # → False
a_list < c_list # → True
操作符: 优先级
# 和学校学的算数一样, 乘除的优先级高于加减, 括号决定了计算的优先级
1 + 3 * 2 # → 7
(1 + 3) * 2 # → 8
容器
列表的操作
# 用列表(list)储存序列
li = []
# 创建列表时也可以同时赋给元素
other_li = [4, 5, 6]
# 用append在列表最后追加元素
li.append(1) # li 现在是[1]
li.append(2) # li 现在是[1, 2]
li.append(4) # li 现在是[1, 2, 4]
li.append(3) # li 现在是[1, 2, 4, 3]
# 用pop从列表尾部删除,并获得这个尾部的元素
li.pop() # → 3 且 li 现在是[1, 2, 4]
# 把3再放回去
li.append(3) # li 变回[1, 2, 4, 3]
# 列表存取跟数组一样
li[0] # → 1
# 取出最后一个元素
li[-1] # → 3
# 越界存取会造成IndexError
li[4] # 抛出IndexError
# 列表可以切片
# 注意, 切片是从第1个参数指示的索引位置开始, 在第2个参数指示的索引位置之前就结束
# 所以, 下面的切片只取了第 1、2 个索引位置上的数
li[1:3] # → [2, 4]
# 取尾
li[2:] # → [4, 3]
# 取头
li[:3] # → [1, 2, 4]
# 隔一个取一个, 也就是步长为 2. 注意, 原有列表的值不变
li[::2] # →[1, 4]
# 倒序排列, 也就是步长为 -1. 注意, 原有列表的值不变
li[::-1] # → [3, 4, 2, 1]
# 可以用三个参数的任何组合来构建切片
# li[始:终:步伐]
# 用del删除任何一个元素
del li[2] # li 现在是 [1, 2, 3]
# 列表可以相加
# 注意: li 和 other_li的值都不变
li + other_li # → [1, 2, 3, 4, 5, 6]
# 可以操作符 + 来拼接列表
li + other_li # li现在是[1, 2, 3, 4, 5, 6]
# 也可以用 extend 拼接列表
li.extend(other_li) # li现在是[1, 2, 3, 4, 5, 6]
# 用in测试列表是否包含值
1 in li # → True
# 用len取列表长度
len(li) # → 6
元组的操作
# 元组是不可改变的序列
tup = (1, 2, 3)
tup[0] # → 1
tup[0] = 3 # 报错, TypeError, 因为元组不能被修改
# 列表允许的操作, 元组大部分都可以使用
len(tup) # → 3
tup + (4, 5, 6) # → (1, 2, 3, 4, 5, 6)
tup[:2] # → (1, 2)
2 in tup # → True
# 可以把元组合列表解包, 赋值给变量
a, b, c = (1, 2, 3) # 现在a是1, b是2, c是3
# 元组周围的括号是可以省略的
d, e, f = 4, 5, 6
# 交换两个变量的值就这么简单
e, d = d, e # 现在d是5, e是4
字典的操作
# 用字典表达映射关系
empty_dict = {}
# 字典的初始化
filled_dict = {"one": 1, "two": 2, "three": 3}
# 用[]取值
filled_dict["one"] # → 1
# 用 keys 可以获得该字典所有的键
# 因为 keys 返回的是一个可迭代对象, 所以在这里把结果包在 list 里
# 注意: 和列表不同, 字典的键的顺序是不定的, 你得到的结果可能和下面不一样
list(filled_dict.keys()) # → ["three", "two", "one"]
# 用 values 可以获得所有的值. 跟keys一样, 这里用list包起来, 顺序也可能不同
list(filled_dict.values()) # → [3, 2, 1]
# 用 in 测试一个字典是否包含一个键
"one" in filled_dict # → True
1 in filled_dict # → False
# 访问不存在的键会导致 KeyError
filled_dict["four"] # KeyError
# 用 get 来避免 KeyError
filled_dict.get("one") # → 1
filled_dict.get("four") # → None
# 当键不存在的时候, get方法可以返回默认值
filled_dict.get("one", 4) # → 1
filled_dict.get("four", 4) # → 4
# setdefault 方法只有当键不存在的时候插入新值
filled_dict.setdefault("five", 5) # filled_dict["five"]设为5
filled_dict.setdefault("five", 6) # filled_dict["five"]还是5
# 字典赋值
filled_dict.update({"four":4}) # → {"one": 1, "two": 2, "three": 3, "four": 4}
filled_dict["four"] = 4 # 另一种赋值方法
# 用 del 删除键值对
del filled_dict["one"] # 从 filled_dict 中把 "one": 1 的键值对删除
集合的操作
# 用set表达集合
empty_set = set()
# 初始化一个集合, 和字典的初始化相似
some_set = {1, 1, 2, 2, 3, 4} # some_set现在是{1, 2, 3, 4}
# 可以把集合赋值给变量
filled_set = some_set
# 向集合添加元素
filled_set.add(5) # filled_set现在是{1, 2, 3, 4, 5}
# 用 & 取集合的交集
other_set = {3, 4, 5, 6}
filled_set & other_set # → {3, 4, 5}
# 用 | 取集合的并集
filled_set | other_set # → {1, 2, 3, 4, 5, 6}
# 用 - 取集合的补集
{1, 2, 3, 4} - {2, 3, 5} # → {1, 4}
# 用 in 测试集合中是否包含某元素
2 in filled_set # → True
10 in filled_set # → False
输入输出
获取输入
# 获取用户输入的内容
a = input('请输入你的名字')
b = input('请输入你的年龄')
print("Welcome {name}! Your age is {age}.".format(name=a, age=b))
格式化输出
# print是内置的打印函数
print("Hello World!") # → Hello World!
a = 'you'
b = 'me'
print(a, 'and', b, '.') # → you and me .
print(a, ' and ', b, '.', sep='', end='\n') # → you and me.
# 用.format来格式化字符串
"{} can be {}".format("strings", "interpolated")
# 可以重复使用相同的参数
"我喜欢{0}, 爸爸也喜欢{0}, 妈妈喜欢{1}".format("苹果", "梨")
# → "我喜欢苹果, 爸爸也喜欢苹果, 妈妈喜欢梨"
# 如果不想数参数, 可以用关键字
"{name} wants to eat {food}".format(name="Bob", food="lasagna")
# → "Bob wants to eat lasagna"
# 如果要输出多行字符串, 除了写一条一条语句之外, 还可以
message = """Hello, {name}
Sincerely, {me}"""
print (message.format(name = "Jake", me = "Sally"))
# 输出:
# Hello, Jake
# Sincerely, Sally
# 如果你的Python3程序也要在Python2.5以下环境运行
# 也可以用老式的格式化语法
# %s 表示string字符串, %d 表示digit数字, %f 表示float浮点数
"%s can be %s the %s way" % ("strings", "interpolated", "old")
流程控制
流程控制: 判断
# 注意 "elif" 的写法, 它表示 else if
some_var = 5
if some_var > 10: #定义一个判断条件
print("some_var 比 10 大")
elif some_var < 10: # elif是可选的
print("some_var 比 10 小")
else: # else也是可选的
print("some_var 和 10 相等")
流程控制: 循环
# 有 2 种循环:
# - for 循环
# - while 循环
# for循环
# 用for循环遍历列表
for friends in ["李雷", "韩梅梅", "张华", "李萍"]:
print("{}是我的朋友".format(friends))
# 打印结果:
"""
李雷是我的朋友
韩梅梅是我的朋友
张华是我的朋友
李萍是我的朋友
"""
# range 函数
# 用 range 函数生成列表, 用于for循环的迭代
for i in range(4):
print(i)
# 打印结果:
"""
0
1
2
3
"""
for i in range(1,7,2): # range(起始, 结尾, 步长), 注意, 切片在声明的结尾之前就结束了
print(i)
# 打印结果:
"""
1
3
5
"""
# 注意, 上面的打印结果中没有 7, 因为在 7 之前就结束了
# while 循环
x = 0
while x < 4:
print(x)
x += 1 # x = x + 1 的简写
# 打印结果:
"""
0
1
2
3
"""
流程控制: 异常
# 用 try/except 来处理“异常”, 也就是通常理解的“错误”
try:
raise IndexError("This is an index error") # 用raise抛出异常
except IndexError as e:
pass # pass是无操作, 但是应该在这里处理错误
except (TypeError, NameError): # 可以同时处理不同类的错误
pass
else: # else 语句是可选的, 必须在所有的except之后
print("All good!") # 只有当try运行完没有错误的时候这句才会运行
可迭代对象
可迭代(iterable)的对象可以作为序列的对象, 比如上面的 range() 函数返回的对象就是可迭代的
filled_dict = {"one": 1, "two": 2, "three": 3}
our_iterable = filled_dict.keys()
print(our_iterable) # → dict_keys(['one', 'two', 'three']), 是一个可迭代对象
# 可迭代的对象可以遍历
for i in our_iterable:
print(i) # 打印 one, two, three
# 但是不可以随机访问
our_iterable[1] # 报错, 抛出TypeError
# 可迭代对象知道怎么生成迭代器
our_iterator = iter(our_iterable)
# 迭代器是一个可以记住遍历的位置的对象
# 用 __next__ 可以取得下一个元素
our_iterator.__next__() # → "one"
# 再一次调取__next__时会记得上一次的位置
our_iterator.__next__() # → "two"
our_iterator.__next__() # → "three"
# 当迭代器所有元素都取出后, 会抛出StopIteration
our_iterator.__next__() # 抛出StopIteration
# 可以用list一次取出迭代器所有的元素
list(filled_dict.keys()) # → Returns ["one", "two", "three"]
组织代码
组织代码: 函数
# 定义函数
def add(x, y):
print("x is {} and y is {}".format(x, y))
return x + y # 用return语句返回
# 调用函数
add(5, 6) # → 印出"x is 5 and y is 6"并且返回11
# 也可以用关键字参数来调用函数
add(y=6, x=5) # 关键字参数可以用任何顺序
add(x=5, y=6)
# 可变参数
# 我们可以定义一个可变参数的函数, 即参数数量不用写死
def varargs(*args):
return args
varargs(1, 2, 3) # → (1, 2, 3)
varargs(1, 2, 3, 4) # → (1, 2, 3, 4)
# 我们也可以定义一个关键字可变参数的函数
def keyword_args(**kwargs):
return kwargs
keyword_args(big="foot", loch="ness") # → {"big": "foot", "loch": "ness"}
# 这两种可变参数可以混着用
def all_the_args(*args, **kwargs):
print(args)
print(kwargs)
all_the_args(1, 2, a=3, b=4)
# 输出:
"""
(1, 2)
{'a': 3, 'b': 4}
"""
# 调用可变参数函数时可以做跟上面相反的, 用*展开序列, 用**展开字典
args = (1, 2, 3, 4)
kwargs = {"a": 3, "b": 4}
all_the_args(*args) # 相当于 all_the_args(1, 2, 3, 4)
all_the_args(**kwargs) # 相当于 all_the_args(a=3, b=4)
all_the_args(*args, **kwargs) # 相当于 all_the_args(1, 2, 3, 4, a=3, b=4)
# 函数的作用域
x = 5
def setLocalX(num):
x = num # → 43, 这是局部作用域的 x, 和全局作用域的 x 不同
print (x) # → 43
def setGlobalX(num):
global x # 声明为为全局变量
print (x) # → 5
x = num # 全局作用域的 x 的赋值被修改
print (x) # → 6
setLocalX(43) # 输出 43
setGlobalX(6) # 输出 5 6
# 函数在 Python 中是一等公民
def create_adder(x):
def adder(y):
return x + y
return adder
add_10 = create_adder(10)
add_10(3) # → 13
# 匿名函数
# 可以用 lambda 关键字来写匿名函数, 可以让函数的代码非常简洁
# 通常的函数写法:
def compare (x):
return x >2
compare (3) # → True
# lambada 匿名函数的写法:
compare = lambda x : x>2
compare(3) # → True
# 内置的高阶函数
map(add_10, [1, 2, 3]) # → [11, 12, 13]
filter(lambda x: x > 5, [3, 4, 5, 6, 7]) # → [6, 7]
# 用列表推导式可以简化映射和过滤. 列表推导式的返回值是另一个列表
[add_10(i) for i in [1, 2, 3]] # → [11, 12, 13]
[x for x in [3, 4, 5, 6, 7] if x > 5] # → [6, 7]
组织代码: 类
# 定义一个继承object的类
class Human(object):
# 类的属性, 被所有此类的实例共用.
species = "H. sapiens"
# 构造方法, 当有实例被初始化时, 就会被调用
# 名字前后的双下划线, 表明这个属性或者方法对Python有特殊意义
# 通常我们自己定义的名字不应该以下划线开头
def __init__(self, name):
# 将参数赋值给实例的属性
self.name = name
# 实例的方法, 第一个参数总是self, 就是这个实例对象
def say(self, msg):
return "{name}: {message}".format(name=self.name, message=msg)
# 类方法, 被所有此类的实例共用. 第一个参数是这个类对象
@classmethod
def get_species(cls):
return cls.species
# 静态方法. 调用时没有实例或类的绑定
@staticmethod
def grunt():
return "*grunt*"
# 构造一个实例
i = Human(name="Ian")
print(i.say("hi")) # → "Ian: hi"
j = Human("Joel")
print(j.say("hello")) # → "Joel: hello"
# 调用一个类方法
i.get_species() # → "H. sapiens"
# 改一个共用的类属性
Human.species = "H. neanderthalensis"
i.get_species() # → "H. neanderthalensis"
j.get_species() # → "H. neanderthalensis"
# 调用静态方法
Human.grunt() # → "*grunt*"
组织代码: 模块
# 用import导入模块
import math # 导入math数学模块, 才能调用开平方的 sqrt() 方法
print(math.sqrt(16)) # → 4.0
# 也可以从模块中导入指定的方法
from math import ceil, floor
print(ceil(3.7)) # → 4.0; 调用的时候, 只要写成 ceil(), 不用写成 math.ceil()
print(floor(3.7)) # → 3.0
# 你可以这样列出一个模块里所有的值
import math
dir(math)
# 可以导入一个模块中所有值
# 警告: 不建议这么做
from math import *
# 可以为模块设置别名
import math as m
math.sqrt(16) == m.sqrt(16) # → True
# Python 模块的本质就是一个 Python 文件, import 就相当于导入这个文件
# 我们可以自己写一个 Python 文件, 然后将其作为模块导入
# 模块的名称就是文件的名字
高阶用法: 生成器 & 装饰器
# 生成器(generators)
# 用生成器可以方便地写惰性运算
def double_numbers(iterable):
for i in iterable:
yield i + i
# 生成器只有在需要时才计算下一个值
# 它们每一次循环只生成一个值, 而不是把所有的值全部算好
# range的返回值也是一个生成器
# 不然一个1到900000000的列表会花很多时间和内存
# 如果你想用一个Python的关键字当作变量名, 可以加一个下划线来区分
range_ = range(1, 900000000)
# 当找到一个 >=30 的结果就会停
# 这意味着 `double_numbers` 不会生成大于30的数
for i in double_numbers(range_):
print(i)
if i >= 30:
break
# 装饰器(decorators)
# 下面这个例子中, beg装饰say
# beg会先调用say. 如果返回的say_please为真, beg会改变返回的字符串
from functools import wraps
def beg(target_function):
@wraps(target_function)
def wrapper(*args, **kwargs):
msg, say_please = target_function(*args, **kwargs)
if say_please:
return "{} {}".format(msg, "Please! I am poor :(")
return msg
return wrapper
@beg
def say(say_please=False):
msg = "Can you buy me a beer?"
return msg, say_please
print(say()) # Can you buy me a beer?
print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :(