Python急救
本文用于期末急救Python。
在开始前你需要知道的
Python急救不是给那些想要完整的了解Python基础语法和基础内置函数的人准备的,而是给已经到期末马上就要考试但啥也不会的人准备的。
这里涉及的知识非常不全,即便是应付考试也不是非常全面,只为了你在考试的时候不至于什么都不会。
如果你还有时间,我建议你阅读:
我尽可能的完整的引入专业词汇的概念,减少阅读障碍,如果你真的完全没有任何基础,阅读本文时务必不要快进任何内容。
本文其实是针对某大学某校区的Python期末考试写的。
任何语言都是强类型依赖的,只不过是类型的约束强弱有别,因此对于一个你要传入参数的地方,知道他要求的类型和你有的数据的类型是第一步。
善用IDLE
当你输入一个函数之后,IDLE会告诉你它的用法,当你不知道用法但你知道函数功能的时候你就可以参考这个来写代码,这非常有用。
当你不知道一个全名或者太长懒得打字,你可以摁Tab找到你需要的函数或者变量的名字然后回车,IDLE会自动帮你输入,这可以大幅度减少你打错字的概率并且帮助你更快的写代码。
写完主观题代码一定要测试一遍,并且时间充裕的情况下你应该尝试多组输入,并检查他们的输出!
善用VSCode
尽管机考时你可能无法使用它,但这真的是非常好用的工具,可以很大程度的方便你学习Python和其他语言,也很方便你进行编程,你至少应该学会怎么打断点进行调试吧。
不要害怕造轮子
在主观题中如果你知道有一个函数可以实现你想实现的功能,但你忘了是什么,在万不得已的情况下不要害怕把它的功能用你自己的方式重现一遍,这在关键时刻可能会对你解题有帮助。
但你的代码很可能效率或功能不如原本的“轮子”,所以不是在万不得已不要这样做。
类型
如同一句话有名词动词,有主谓宾等成分,在Python中也有很多类型,我们称之为Type,你可以很容易的通过type()知道一个变量的类型,比如:
1 | a = 1 |
你应该会看到python告诉你a的类型是int,即为数字,这里我没告诉python变量类型是什么,int类型是他根据我输入的1推测出来的。Python考试中常见的类型如下:
| 类型 | 声明方法 | 例子 |
|---|---|---|
| 整数(int) | int() | a = 1 |
| 浮点数(float) | float() | a = 1.0 |
| 字符串(str) | str() | a = “abc” |
| 列表(list) | list() | a = [1, 2, 3] |
| 字典(dict) | dict() | a = {“a”: 1, “b”: 2} |
| 元组(tuple) | tuple() | a = (1, 2, 3) |
| 集合(set) | set() | a = {1, 2, 3},但空集合必须用a = set(),因为空字典用的是a = {} |
| 布尔值(Bool) | bool() | 常见的情况就是True和False,其他的下文描述。 |
我们很容易注意到声明方法中的都很像(其实就是)函数,因此只要你知道现在你有的某一个变量很确定且必须转换成另一个变量,你可以直接用这些方法转换。
这些类型除了布尔值、整数和浮点数都能迭代,这对解题尤其是主观题非常有帮助,包括字符串,迭代的含义其实非常简单,就是将其中的元素一个一个的取出来,比如这个代码:
1 | a = "abc" |
他会输出:
1 | a |
我们看到i被分别赋值为a、b和c,对于列表等其他类型也是如此,他会一次次的取出其中的每一项赋值给i。
接下来我们一个个解释类型和其常见的方法。
赋值
Python最简单的赋值方法就是:
1 | a = 0 |
Python赋值的一个技巧可以简单的将两个变量值交换:
1 | a, b = b, a |
还可以把一个容器中的值快速的赋值给变量,但要注意变量数必须对应容器中的元素数:
1 | a, b = [1, 2] |
a和b就是1和2了。
整数和浮点数
数字没什么特殊的用法,你要知道存在几个方便运算的函数即可:
| 函数 | 作用 | 示例 |
|---|---|---|
| abs | 取绝对值 | abs(-100) |
| round | 四舍五入(和常规的有细微差别) | round(x, 2)为对x做保留两位小数,若没有第二个参数2, 则为取整数,若第二个参数是0,则结果为保留到整数的浮点数。 |
| int | 向0取整 | int(x) |
| hex | 整数转十六进制 | hex(x) |
| oct | 整数转八进制 | oct(x) |
你需要知道十六进制数字里面可以有字母(作为不够的数字的替代),而八进制数字是没有字母也没有8和9的。
字符串
字符串可以被单引号包裹也可以被双引号包裹。被引号包裹的数字不是数字类型是字符串类型!!!!!!!
字符串可以切片,很容易理解,就是把它切开不同的部分再取走,比如你想要字符串的前2位:
1 | a = "abc" |
b的值就是ab。
切片具体的参数长这样:
1 | string[start:stop:step] |
你也可以只取其中的某一个字符,像这样:
1 | a = "abc" |
b取到的就是b。
你在题里可能会看到有两个冒号的情况,那就是其中某些参数被省略了,从例子看更直观:
1 | text = "Hello, World!" |
Python的索引是从0开始的!!!!!!!!
字符串常用的函数如下:
| 函数 | 作用 | 例子 |
|---|---|---|
| xxx.lower | 把字符串中的大写字母全部转为小写。 | xxx.lower(“ABC”) |
| xxx.upper | 把字符串中的大写字母全部转为大写。 | xxx.upper(“abc”) |
| xxx.split | 把字符串切成列表,我们会在后面仔细说它的用法,你现在没必要完全掌握。 | xxx.split(“abc”, “”) |
| xxx.isspace | 如果一个字符串是空,就返回布尔值True,反之则False。 | xxx.isspace(“abc”, “”) |
| xxx.rjust | 向一个字符串右侧填充我们要求的字符直到我们要求的数量。 | xxx.rjust(5, “0”),即填充至字符串总长度为5,填充0。 |
| xxx.ljust | 向一个字符串左侧填充我们要求的字符直到我们要求的数量。 | xxx.ljust(5, “0”),即填充至字符串总长度为5,填充0。 |
返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串
这里所有的xxx都要换成你真的操作的字符串的名字(即它的引用)。
字符串中有一些常见的符号,他们被赋予了特殊的含义,这里写的同样非常不全:
| 符号 | 含义 |
|---|---|
| \n | 换行 |
| \“ | 双引号 |
| \‘ | 单引号 |
| \b | 退格 |
列表
列表非常有用,列表里面能套列表形成二维列表,二维列表再套一个形成三维列表。
我们尽可能用最好用的(可能是之一?)列表操作方式——列表推导式。
列表推导式的第一项通常为变量或者表达式,甚至可以是字典的键值对(对于字典而言),第二项(和第一项用空格分开)多半是个for in语句:
1 | [表达式 for 元素 in 可迭代对象 if 条件] |
比如生成一个0到5的列表:
1 | [i for i in range(6)] |
这里我要提示你,range的用法见此:Python range() 函数 | 菜鸟教程,这个你真的不能跳过阅读。
他甚至可以快速生成一个二维列表:
1 | [[0]*3 for i in range(3)] |
它的输出是:
1 | [[0, 0, 0], [0, 0, 0], [0, 0, 0]] |
看不太懂吗,这样呢?
1 | [[0, 0, 0], |
现在它的每一行,从0开始到2,每一列从0开始到2,如果我想取第n行第k列的元素,假如这个列表名字为l,那么我只需要:
1 | l[n][k] |
列表推导式的功能非常强大,还有一个常见的用途是改变列表中所有元素的类型:
1 | a = [1, 2, 3] |
我们非常轻松的把每一个元素的类型都从数字改为了字符串。
为什么要这样做,因为列表一个非常重要的用法:
1 | print("\n".join(a)) |
这将会在a的每两个元素中间插入我们指定的\n,如果你想插入别的也完全可以,比如什么都不写让他们合在一起输出,又或者是用逗号分开,完全没问题。但只有列表中所有元素都是字符串类型才可以这样做,这也是为什么我们刚刚要转换的原因。
列表还能被转换成其他类型的可迭代对象。
列表常见的函数如下:
| 函数 | 功能 | 示例 |
|---|---|---|
| xxx.pop | 返回指定序列号的元素并删除。 | xxx.pop(0) |
| xxx.append | 在末尾加入新元素。 | xxx.append(“a”) |
| xxx.insert | 于新元素插入列表的指定位置。 | xxx.insert(3, “a”) 第一个参数为位置第二个为内容。 |
| xxx.remove | 删除第一个匹配的元素。 | xxx.remove(“a”) |
| xxx.index | 返回第一个匹配的元素的位置。 | xxx.index(“a”) |
| xxx.count | 数元素在列表中出现了几次。 | xxx.count(“a”) |
| xxx.extend | 把另一个列表里面的内容复制到这个列表的尾部。 | xxx.extend(l) |
| xxx.reverse | 反向列表中元素。 | xxx.reverse(l) |
xxx依旧替换为实际操作的列表。
另外,非常重要的函数,sort:
如果你想对一个列表中的元素排序,你只需要:
1 | list.sort(key=None, reverse=False) |
- key – 排序的元素。
- reverse – 排序规则,reverse = True 降序, reverse = False 升序(默认)。
这里涉及到一个问题,key是什么,key是决定以什么元素来排序的方法,key后面跟着的一定是一个函数,而不是函数的返回值,也就是要么你写一个函数在这里,要么你写一个函数的名字在这里,通常我们用lambda匿名函数写法,如果你列表里面只是数字,那完全没有写这个的必要,lambda我们会在后文讲。
del也能删列表的元素,就像是:
1 | del l[0] |
字典
我们之前提到列表是由索引的数字来索引的,而字典就是由一个键索引的,它可以是一个数字,也可以是一个字符串。
字典就像是真实的字典,一个字典的键不能重复,但值是可以的。
在Python3.5及其之前字典都是无序的,但是在之后就有序了,意味着我们可以对他们进行排序,就像这样:
1 | a = {"a": 1, "b": 3, "c": 2} |
这几行我们将逐步解释,这是你学习字典不错的例子。
第一行是字典的声明,第二行我们拆分来看,先从最内侧的函数返回值sorted讲起,这是一个用于排序有序容器的函数,a.items返回了一个列表,其中的元素是一个个元组构成的键值对,就像是:
1 | [("a", 1), ...] |
后面的key的用法和之前提到的list的sort方法中的key相似,引入一个lambda匿名函数,输入的是items中的每一个元组,输出的是其中的第二项,也就是值的一项,并以值的大小进行排序(lambda的用法我们会在后面详细描述,这里不要求你完全明白),然后外侧的dict就很好理解,把这个列表再转换回字典。
我们在这里也可以用推导式:
1 | a = {v: k for k, v in a.items()} |
这里的意思就是把items中本来在键的内容放在了值,值的内容放在了键,进行了交换,但如果字典中有重复值的话,那你可能需要多考虑一点。
字典的元素访问非常简单:
1 | d1 = {"a": 1, "b": 2} |
不要忘记引号!
字典添加和修改内容直接通过给键赋值即可。
1 | del d1['a'] # 删除键'a'及其对应的值 |
字典对键的要求是不可变即可,那么元组(我们接下来会介绍的)、数字和字符串都是可以的,但列表就不行(因为可变)。
对于字典,由于本教程的性质,你了解items就够你完成很多主观题了,如果你有兴趣看其他的函数和方法请看Python 字典(Dictionary) | 菜鸟教程。
元组
元组就是个不可变的列表,但你要知道他不可变不代表他含有的元素不可变,不可变性是不具备继承能力的,元组中的列表等可变的元素依旧可以修改。
元组长这样:
1 | a = (1, 2, 3) |
集合
集合和数学中的十分相似,最有用的就是对列表中的元素去重,你只需要先把列表转为集合再转为列表就能快速的去掉重复元素。但集合是无序的!!!!!
集合可以进行交集、并集、差集等操作:
交集: & 运算符或intersection()方法
并集: | 运算符或union()方法
差集: -运算符或difference()方法
补集: ^ 运算符或symmetric_difference()方法
这里同样不再写其他内置函数用法了,如果你有时间看自行查阅。
共性
在讲布尔值之前,以上除了数字,都有一些通用的函数:
| 函数 | 功能 | 示例 |
|---|---|---|
| len | 返回长度,字符串就是字符个数,容器就是元素个数。 | len(a) |
布尔值
简单来说就是计算机判断正确与否的一个类型,整数是可以转换成布尔值的,非0的都是真(True),0是假(False)。
布尔值对流程控制非常好用,我们待会会说,除此之外它简直是最简单的类型之一。
流程控制
流程控制就是类似工厂的流水线,某些代码是重复的,我们不想写太多次,某些代码是有选择性执行的,我们需要判断。
循环类的
while是最常见的循环方式吗,当while语句后面跟随的布尔值是真,就一直执行,直到判断为假:
1 | while True: |
这段代码在用户关掉程序之前会无休止的执行,while会在执行前判断后面的布尔值是否是真,如果不是就一次也不执行,直接跳过。
for循环是很有用的循环类型,他其实是一次一次的将一个容器中的值一个个的取出来并赋值给某个变量再去执行代码,如果容器还能按照要求取出东西,那就会一直执行,如果取不出就结束执行。
比如最简单的打印0到5:
1 | for i in range(6): |
range最基础的用法是:
1 | range(a, b) |
返回一个a到b-1的序列,就这么简单。
在a不存在的情况下就是0到b-1。
for循环还能从字符串或容器中取出字母或元素,这样能保证你永远不会取到容器中不存在的元素(通常由于错误的操作索引导致):
1 | a = [1, 2] |
当循环不需要给类似i这样的变量赋值的时候,你就把i那个位置改成_,如果你想把i换成别的名字也是完全可以的。
逻辑控制
最基础的逻辑控制就是if和else还有elif,他们的运行优先级是if>elif>else,且除了if都不能单独存在,elif和else都是可选的,if和elif后面的布尔值如果是True才可能运行,且elif如果想运行if后的布尔值一定为False。只有所有的if和elif全都不能执行else才能执行,写法看起来像这样:
1 | a = 1 |
这里我们看到了判断的符号,当成立的时候他们返回True,反之则False,常见的如下:
| 符号 | 作用 |
|---|---|
| == | 相等 |
| > | 大于 |
| >= | 大于等于 |
| < | 小于 |
| <= | 小于等于 |
| != | 不等于 |
| in | 在xxx之中(常见于字符串和容器)。 |
| not | 不,在后面的条件不符合的时候返回True。 |
| or | 两个判断并列,只要有一个符合就返回True。 |
| and | 两个判断并列,两个都要符合才返回True。 |
千万别把判断的==和赋值的=搞混了!!!
输入和输出
作为程序,IO是非常重要的(input和output)。
输入
python最常见的输入方式是用户在终端打字输入,有个函数专门处理这些,就是input。
这个函数的返回值类型是字符串,因此如果输入的是数字,你要先把它转换成数字类型才能当一般数字处理。
输出
输出最常见的是print,print函数的用法很简单:
1 | print(*objects, sep=' ', end='\n') |
我这里没给出所有的参数,只给出了常见的,objects的意思是你可以在这里面用逗号分隔放很多很多个不同的东西进来,sep是分隔这些东西的符号,end是print在这些东西最后放的字符,默认是回车,当你不需要换行的时候就把end设置为啥也没有的字符串。
输出数字时经常会让你保留几位小数,除了我们之前在数字类型部分提到的方法之外还有个叫格式化的东西:
1 | num1 = 3.14159 |
这是保留两位小数,三位四位什么的你改那个数字就行了,由于本教程的性质我不进行解释,如果你好奇请自己搜索。
运算符号
+号是加法,不但能加数字,还能把两个字符串和在一起,往一个可变容器里面加东西:
1 | a = [] |
a就变成[1]了。
*是乘法,不但能乘数字,还能让字符串重复几次,还能让列表也重复,比如:
1 | [0]*3 |
/是除法,对数字操作默认返回浮点数,即便除得开。//也是除法,对整数数字操作返回向下取整的整数类型,但如果除数和被除数有float则返回的是向下取整的float类型。%是取模,返回除法的余数。
**是乘方运算。
函数
函数和数学里面的其实很类似,给一个输入,但在这里不一定给一个输出,函数其实是把一部分代码进行打包。
普通的函数
定义一个函数很简单:
1 | def a(a1, a2): |
这里定义了一个函数a,传入两个参数a1和a2,返回了a1+a2.
返回不是打印!!!!!!返回是返回!!!!!!
获取返回值也很简单,对于刚才那个函数:
1 | a(1, 2) |
就获得了当输入1, 2时候的返回值,它们按顺序对应a1和a2。
而要打印函数的返回值要这样:
1 | print(a(1, 2)) |
函数内的变量在大多数情况下是不会直接影响函数外的!!!!!!
函数是可以有多个返回的,一个return语句也可以有多个内容返回。
匿名函数
lambda是匿名函数,可以直接写在某个需要函数作为输入的地方,特别适合简单的功能。
1 | a = lambda x:x[1] |
lambda函数的输入在冒号左侧,输出在冒号右侧。且必须写lambda字样。
编程题解题常见方法
计算机执行任务去解决问题,有几种常见的解题思路,由于本教程仅仅为了完成期末考试涉及的常见题目,因此我仅仅介绍常见的。
在开始之前你要明白
计算机的计算速度很快,期末考试题的测试样本一般没那么大(可能吧),而且没有特别严格的运行时空限制(Time和RAM占用),因此你当你真的没办法的时候可以尝试写一些大力出奇迹的代码来通过考试。
模拟
这是最容易理解的方法,即用计算机模拟人的行为进行批量操作,这种写法的好处在于你只要写一些模仿人类解决这种问题的代码就行了,坏处在于代码可能变得非常复杂且很长,你得权衡的考虑。
比如题目要求你写一个数字三角形,输入10的时候,输出看起来像是:
1 | 1 |
看起来很难吗?我们一点一点分析,首先我们看到程序输出的数字是从1到行数再回到1,同时每一行前面的空格数字都是总行数-当前行数,那么让我们一点一点写,首先获得用户输入:
1 | n = int(input()) |
然后写一个重复n次的循环,来输出n行:
1 | for i in range(1, n + 1): |
这里的i是行数,从1开始到n结束
然后这个循环每一次执行就是在输出每一行,我们只考虑其中的一行来写代码,我们要打印空格,在循环中加上:
1 | print(' ' * (n - i), end='') |
我们刚刚说,每一次循环都是打印一行,这行还没结束,所以我们通过end参数不换行。
然后我们要打印数字了,这里我们看到他先从1到行数,再从行数-1回到1,那我们写列表的join就能输出了,利用列表推导式就能写的非常简单:
1 | print("".join([str(j) for j in range(1, i+1)]), end='') |
我们之前说过join方法只能join字符串为元素构成的列表,所以我们用列表推导式先生成并打印了一个从1到行数的列表元素组合形成的字符串,然后不换行的再输出一个从行数-1到1的字符串,这里range的步长是-1以倒序输出序列,range的用法你应该去搜索和学习。由于最后一部分输出完我们就要进入下一个循环输出下一行了,所以我们不指定end,让其默认进行换行操作。
整体代码看起来像:
1 | n = int(input()) |
如果你想压缩代码行数,甚至可以写成:
1 | n = int(input()) |
但这样可读性略差,没什么必要。
学会了这个,左对齐右对齐的数字三角形也是同理的了,并且不难,你可以自己尝试一下。
枚举
当你需要找出一个解的时候,你不知道有什么特别聪明的办法找到它,那你就把所有的可能全部都尝试一遍找到那个解。
但你要知道不要测试完全没必要的区间,这会大大增加计算的时间。
比如我们想知道一个字符串是否完全由其本身的某一部分重复得到,我们不知道有什么聪明的办法解决,那就每次多取一个字符,从第0个字符开始取,逐步增加字符数,并且检查这个分割出来的字符串重复到原本字符串长度后是否和原本字符串相等,对于样本量不大的检测来说枚举是完全可以的,示例函数如下,函数输入参数为字符串,返回类型为布尔值:
1 | def f(s): |
这个函数不难理解,我们不需要测试整个字符串的分割,最多分到1/2处就够了,因为最少的循环次数是两次。而为什么else写在整个for循环的外侧而不是和if同级,因为我们需要检测所有的if都不成立才能够且确定执行else,否则一种if的情况不可能就直接判断输出结果是False,太荒谬了。
递归
其实在这里并不想写递归操作,但考试又不一定会不会考,因此我讲最简单的写法。
递归就是函数自己使用自己本身的一种方法,最常见的例子之一就是把一个字符串翻转过来:
1 | def reverseastr(s): |
这个函数的意思是当s不为空字符串时,把s的第一位放在最后,再把剩下的部分再扔给这个函数,这个函数会把新输入的这个的第一位再放到最后,直到无字符串可操作的时候,整个字符串就被翻转了,假设输入的是abc:
第一次abc中的a被拿了出来放在了最后,bc被送入函数进行下一次操作。
第二次bc中的b被拿出来放在了最后,a被送入函数进行下一次操作。
第三次c被拿出来放在了最后,没有东西被送入下一个操作。
第四次函数接受到的字符串是空的,递归结束了,输出cba。
在写递归代码的时候不要想太多次操作,想几次认为可行就坚定的写下去,因为人脑是很难处理太多层的。
递归的比较专业的定义是这样的,如果你能理解那最好,不能理解,那就先看别的吧:
1 | def func(传入数值) { |
这里最小子问题对于刚才的例子而言就是字符串输入为空时候的返回值,那就应该是那个空字符串本身,这就是最小子问题解。
在学递归的时候善用VSCode的调试功能。
写在最后的话?
这个教程作为学习Python很不完善,更适合什么都不会的情况下在考前紧急学习。
但如果能帮到你的话,那就足够了。