基于 Learn X in Y minutes 进行修改
注释
# 单行注释: 用井字符开头# 多行注释: 需要用 3 个双引号或者单引号包裹"""多行字符串用三个引号包裹也常被用来做多行注释可以是单引号, 也可以是双引号注意, 必须是英文符号"""# 在调试代码时, 经常把某一部分代码注释掉, 来临时跳过某些代码, 进行对比测试
数据类型
# Python的数据类型:# 整数 int# 浮点数 float# 字符串 str# 布尔值 bool# 数组 array# 元组 turple# 字典 dict# 集合 set# 空对象 None# 用来获取数据类型的函数type()# 整数 integer3 # → 3type(3) # → <class 'int'>a = int(input('请输入数字')) # 想要获取输入的数字, 记得要转化一下# 浮点数 float1.0 # → 1.0type(1.0) # → <class 'float'># 布尔值 booleanTrue # 注意, True 和 False 都必须是首字母大写Falsetype(True) # → <class 'bool'># 整数也可以当作布尔值0 and 2 # → 0-5 or 0 # → -50 == False # → True2 == True # → False1 == True # → True# 这些值都算是 False: None、0、空字符串、空列表、空字典# 而其他的所有的值都是 True# 注意, 没有所谓空集合, 因为空集合就是空字典 {}bool(0) # → Falsebool("") # → Falsebool([]) # → Falsebool({}) # → False# 字符串 stringtype("Hello World") # → <class 'str'># 字符串用单引号或者双引号都可以"这是个字符串"'这也是个字符串'# 字符串可以被当作列表"This is a string"[0] # → 'T'# 列表 listli = []type(li) # → <class 'list'># 元组 tuple# 元组是不可改变的序列tup = (1, 2, 3)type(tup) # → <class 'tuple'>tup[0] # → 1tup[0] = 3 # 抛出TypeError, 因为元组不能被修改# 字典 dictionaryempty_dict = {}type(empty_dict) # → <class 'dict'># 字典的初始化filled_dict = {"one": 1, "two": 2, "three": 3}# 集合 setempty_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 = 5some_var # → 5# 变量命名也可以包含数字, 但是数字不能放在命名的第 1 位4some_var # 报错, SyntaxError: invalid syntax# 访问未赋值的变量会抛出异常# 参考教程后面“流程控制:异常”的部分, 来学习异常处理some_unknown_var # 抛出NameError# 全局变量global some_var
操作符
操作符: 算术操作符
“操作符”的英文名是 Operator, 也称为“运算符”, 包括算术运算、比较运算、逻辑运算… 但是, 我建议用“操作符”来指称, 而不要用“运算符”来指称.
这是因为“运算”这个词给我们的心理暗示是数学上的加减乘除运算, 我们直观上不会认为比较操作、逻辑操作是一种运算 ( 尽管对于计算机来说, 的确是运算 ), 因此大脑面对“比较运算”和“逻辑运算”这些词的时候会产生不协调感. 而“操作符”是一种中性的表述, “操作”可以包括算术运算、比较、逻辑判断…
# Python 中的算术和我们在学校学的算数没有太大区别1 + 1 # → 28 - 1 # → 710 * 2 # → 20# “除法”例外, 除法的结果会自动转换成浮点数35 / 5 # → 7.05 / 3 # → 1.6666666666666667-5 / 3 # → -1.6666666666666667# 两个斜杠//的叫“整数除法”, 需要向下取整# 本质是 floor 操作, floor = 地板, 也就是说取接近计算结果最近的那个整数5 // 3 # → 15.0 // 3.0 # → 1.0 # 浮点数也可以进行整数除法-5 // 3 # → -2 # 注意这里! 记住, 整数除法的结果都是向下取整, 也就是往小的取整-5.0 // 3.0 # → -2.0# 如果想要截取除法结果的整数部分, 需要使用 math 模块的 trunc 函数import mathmath.trunc(1 / 2) # → 0math.trunc(-5 / 3) # → -1# 浮点数的运算结果也是浮点数3 * 2.0 # → 6.0# 取余数, 也叫“取模”、“模除”7 % 3 # → 1# x 的 y 次方2**4 # → 163**2 # → 9# 平方5**2 # → 259**2 # → 81
操作符: 逻辑操作符
# 布尔值TrueFalse# 逻辑操作符, 注意 and 和 or 都是小写True and False # → FalseFalse or True # → True# 逻辑操作符, 用 not 取非not True # → Falsenot False # → True# 整数也可以当作布尔值0 and 2 # → 0-5 or 0 # → -50 == False # → True2 == True # → False1 == True # → True
操作符: 比较操作符
# 比较大小1 < 10 # → True1 > 10 # → False2 <= 2 # → True2 >= 2 # → True# 用 == 判断是否相等1 == 1 # → True2 == 1 # → False3 = 2 # → 会报错, 因为 = 是表示赋值, == 才是判断是否相等# 用 != 判断是否不等于1 != 1 # → False2 != 1 # → True# 大小比较可以连起来!1 < 2 < 3 # → True2 < 3 < 2 # → False# 当与None进行比较时, 不要用 ==# 要用 is# is 是用来比较两个变量是否指向同一个对象"etc" is None # → FalseNone 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 # → Falsea_list < b_list # → Falsea_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# 越界存取会造成IndexErrorli[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] # → 1tup[0] = 3 # 报错, TypeError, 因为元组不能被修改# 列表允许的操作, 元组大部分都可以使用len(tup) # → 3tup + (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 # → True1 in filled_dict # → False# 访问不存在的键会导致 KeyErrorfilled_dict["four"] # KeyError# 用 get 来避免 KeyErrorfilled_dict.get("one") # → 1filled_dict.get("four") # → None# 当键不存在的时候, get方法可以返回默认值filled_dict.get("one", 4) # → 1filled_dict.get("four", 4) # → 4# setdefault 方法只有当键不存在的时候插入新值filled_dict.setdefault("five", 5) # filled_dict["five"]设为5filled_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 # → True10 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 ifsome_var = 5if 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)# 打印结果:"""0123"""for i in range(1,7,2): # range(起始, 结尾, 步长), 注意, 切片在声明的结尾之前就结束了print(i)# 打印结果:"""135"""# 注意, 上面的打印结果中没有 7, 因为在 7 之前就结束了# while 循环x = 0while x < 4:print(x)x += 1 # x = x + 1 的简写# 打印结果:"""0123"""
流程控制: 异常
# 用 try/except 来处理“异常”, 也就是通常理解的“错误”try:raise IndexError("This is an index error") # 用raise抛出异常except IndexError as e:pass # pass是无操作, 但是应该在这里处理错误except (TypeError, NameError): # 可以同时处理不同类的错误passelse: # 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"# 当迭代器所有元素都取出后, 会抛出StopIterationour_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 argsvarargs(1, 2, 3) # → (1, 2, 3)varargs(1, 2, 3, 4) # → (1, 2, 3, 4)# 我们也可以定义一个关键字可变参数的函数def keyword_args(**kwargs):return kwargskeyword_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 = 5def setLocalX(num):x = num # → 43, 这是局部作用域的 x, 和全局作用域的 x 不同print (x) # → 43def setGlobalX(num):global x # 声明为为全局变量print (x) # → 5x = num # 全局作用域的 x 的赋值被修改print (x) # → 6setLocalX(43) # 输出 43setGlobalX(6) # 输出 5 6# 函数在 Python 中是一等公民def create_adder(x):def adder(y):return x + yreturn adderadd_10 = create_adder(10)add_10(3) # → 13# 匿名函数# 可以用 lambda 关键字来写匿名函数, 可以让函数的代码非常简洁# 通常的函数写法:def compare (x):return x >2compare (3) # → True# lambada 匿名函数的写法:compare = lambda x : x>2compare(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)# 类方法, 被所有此类的实例共用. 第一个参数是这个类对象@classmethoddef get_species(cls):return cls.species# 静态方法. 调用时没有实例或类的绑定@staticmethoddef 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, floorprint(ceil(3.7)) # → 4.0; 调用的时候, 只要写成 ceil(), 不用写成 math.ceil()print(floor(3.7)) # → 3.0# 你可以这样列出一个模块里所有的值import mathdir(math)# 可以导入一个模块中所有值# 警告: 不建议这么做from math import *# 可以为模块设置别名import math as mmath.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 wrapsdef 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 msgreturn wrapper@begdef say(say_please=False):msg = "Can you buy me a beer?"return msg, say_pleaseprint(say()) # Can you buy me a beer?print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :(
