Python学习笔记

Python基础

命令行与交互模式的区别

在交互模式:在windows电脑的cmd下,输入python,即可进入交互模式,前面会有提示符>>>,在提示符后面直接输入代码,按回车,就可以立刻得到代码执行结果。
命令行模式:执行一个.py文件只能在命令行模式执行。如敲一个命令python hello.py。

运算符

and运算是与运算,只有所有都为True,and运算结果才是True。
or运算是或运算,只要其中有一个为True,or运算结果就是True。
not运算是非运算,它是一个单目运算符,把True变成False,False变成True。
在Python交互模式下输入 210 你会得到:
运算符**为幂 ,2
10就是2的10次幂(10次方,一些语言表示为210)210=1024

除法

一种除法是/,即使是两个整数恰好整除,结果也是浮点数:

>>> 10 / 3
3.3333333333333335

>>> 9 / 3
3.0

还有一种除法是//,称为地板除,两个整数的除法仍然是整数:

>>> 10 // 3
3

你没有看错,整数的地板除//永远是整数,即使除不尽。要做精确的除法,使用/就可以。
因为//除法只取结果的整数部分,所以Python还提供一个余数运算%,可以得到两个整数相除的余数:

>>> 10 % 3
1

无论整数做//除法还是%取余数,结果永远是整数,所以,整数运算结果永远是精确的。

Python中的几种数据类型

共有7种数据类型,按照可变与非可变两大类型。

① 非可变类型:非可变类型就是在内存中,内存地址一旦固定,其值就没办法发生任何改变了。
数值(int整型、float浮点类型)
bool类型(True和False)
字符串类型(str)
元组(tuple 1,2,3)

② 可变类型: 可变类型就是在内存中,其内存地址一旦固定,其值是可以发生改变的。
列表(list [1, 2, 3])
字典(dict {key:value})
集合(set {1, 2})

整数

Python可以处理任意大小的整数,当然包括负整数,在程序中的表示方法和数学上的写法一模一样,例如:1100-80800,等等。

计算机由于使用二进制,所以,有时候用十六进制表示整数比较方便,十六进制用0x前缀和0-9a-f表示,例如:0xff000xa5b4c3d2,等等。

对于很大的数,例如10000000000,很难数清楚0的个数。Python允许在数字中间以_分隔,因此,写成10_000_000_00010000000000是完全一样的。十六进制数也可以写成0xa1b2_c3d4

浮点数

浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,比如,1.23x 1 0 9 10^9 109和12.3x 1 0 8 10^8 108是完全相等的。浮点数可以用数学写法,如1.23,3.14,-9.01,等等。但是对于很大或很小的浮点数,就必须用科学计数法表示,把10用e替代,1.23x 1 0 9 10^9 109就是1.23e9,或者12.3e8,0.000012可以写成1.2e-5,等等。

布尔值

一个布尔值只有True、False两种值,布尔值经常用在条件判断中,比如:

if age >= 18:
    print('adult')
else:
    print('teenager')

空值

空值是Python里一个特殊的值,用None表示。None不能理解为0,因为0是有意义的,而None是一个特殊的空值。

变量

变量在程序中就是用一个变量名表示了,变量名必须是大小写英文、数字和_的组合,且不能用数字开头。例如变量名可以是以下这些,都是可以的:

a = 10
ab = 100
a_1b = 1000
Ab_1b = 10000

常量

所谓常量就是不能变的变量,比如常用的数学常数π就是一个常量。在Python中,通常用全部大写的变量名表示常量:

PI = 3.14159265359

但事实上PI仍然是一个变量,Python根本没有任何机制保证PI不会被改变,所以,用全部大写的变量名表示常量只是一个习惯上的用法,如果你一定要改变变量PI的值,也没人能拦住你。

字符串

字符串是以单引号'或双引号"括起来的任意文本,如果字符串内部既包含’又包含"怎么办?可以用转义字符\来标识,比如:

'I\'m \"OK\"!'
或者
"I'm \"OK\"!"

如果期望得到的字符串中本来就带\,也就是说不想让字符串中的\被转义,那么可以采用\\来实现,代表\后面的\不需要转义。也可以使用r' '方法,让' '里面的内容全都不转义,会原封不动的打出来。例如:

s4 = 'Hello, \\"Bart"'
print(s4)	#输出结果为 Hello, \"Bart"

s5 = r'Hello, \"Bart"'
print(s5)	#输出结果为 Hello, \"Bart"

字符、字符串、编码相关知识

因为计算机只能处理数字,字符串是文本,如果要处理文本,就必须先把文本转换为数字才能处理。
8个比特(bit)作为1个字节(byte),所以,一个字节能表示的最大的整数就是255(二进制11111111=十进制255),如果要表示更大的整数,就必须用更多的字节。比如两个字节可以表示的最大整数是65535,4个字节可以表示的最大整数是4294967295。
由于计算机是美国人发明的,因此,最早只有127个字符被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码,比如大写字母A的编码是65,小写字母z的编码是122。
但是要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突,所以,中国制定了GB2312编码,用来把中文编进去。
全世界有上百种语言,日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里,各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。
因此,Unicode字符集应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。
Unicode标准也在不断发展,但最常用的是UCS-16编码,用2个字节表示1个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持Unicode。
新的问题又出现了:如果统一成Unicode编码,乱码问题从此消失了。但是,如果你写的文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间,在存储和传输上就十分不划算。
所以,本着节约的精神,又出现了把Unicode编码转化为“可变长编码”的UTF-8编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间:
在这里插入图片描述
在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。例如:用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件。再例如:浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器。
在操作字符串时,我们经常遇到str和bytes的互相转换。为了避免乱码问题,应当始终坚持使用UTF-8编码对str和bytes进行转换。

字符串的encode和decode方法

Python对bytes类型的数据用带b前缀的单引号或双引号表示

>>> str1 = '这是中文'
>>> print(str1.encode('utf-8'))
b'\xe8\xbf\x99\xe6\x98\xaf\xe4\xb8\xad\xe6\x96\x87'

>>> str2 = b'\xe8\xbf\x99\xe6\x98\xaf\xe4\xb8\xad\xe6\x96\x87'
>>> print(str2.decode('utf-8'))
这是中文

如果bytes中包含无法解码的字节,decode()方法会报错,如果bytes中只有一小部分无效的字节,可以传入errors='ignore’忽略错误的字节:

>>> b'\xe4\xb8\xad\xff'.decode('utf-8')
Traceback (most recent call last):
  ...
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 3: invalid start byte

#添加errors='ignore'即可忽略错误的字节
>>> b'\xe4\xb8\xad\xff'.decode('utf-8', errors='ignore')
'中'

格式化字符串

最后一种格式化字符串的方法是使用以f开头的字符串,称之为f-string,它和普通字符串不同之处在于,字符串如果包含{xxx},就会以对应的变量替换:

>>> r = 2.5
>>> s = 3.14 * r ** 2
>>> print(f'The area of a circle with radius {r} is {s:.2f}')
The area of a circle with radius 2.5 is 19.62

上述代码中,{r}被变量r的值替换,{s:.2f}被变量s的值替换,并且:后面的.2f指定了格式化参数(即保留两位小数),因此,{s:.2f}的替换结果是19.62。

占位符

常见的占位符:

占位符替换内容
%d整数
%f浮点数
%s字符串
%x16进制整数
  • %2d是将数字按宽度为2,采⽤右对齐⽅式输出,若数据位数不到2位,则左边补空格。
  • %02d,和%2d差不多,只不过左边补0。
  • %-2d将数字按宽度为2,采⽤左对齐⽅式输出,若数据位数不到2位,则右边补空格。
  • %.2d 输出整形时最少输出2位,如不够前⾯以0占位。如输出2时变成02,200时只输出200;输出浮点型时(%.2f)小数点后强制两位输出。
>>> print('%2d-%02d' % (3, 1))
 3-01
>>> print('%2d-%-02d' % (3, 1))
3-1
>>> print('%.2f' % 3.1415926)
3.14

有些时候,字符串里面的%是一个普通字符怎么办?这个时候就需要转义,用%%来表示一个%:

>>> 'growth rate: %d %%' % 7
'growth rate: 7 %'

len方法

len()函数计算的是str的字符数,如果换成bytes,len()函数就计算字节数,可见,1个中文字符经过UTF-8编码后通常会占用3个字节,而1个英文字符只占用1个字节

>>> len('ABC')
3
>>> len('中文')
2
>>> len(b'ABC')
3
>>> len(b'\xe4\xb8\xad\xe6\x96\x87')
6
>>> len('中文'.encode('utf-8'))
6

字符串的切割、拼接方法

split方法
对字符串进行切割操作,返回一个list()列表类型的数据

list1 = 'apple-banana-orange'
print(str1.split('-'))

join方法
对字符串进行拼接,返回一个list()列表类型的数据

list2 = 'apple'
print('-'.join(list2))

列表

列表的四种删方法

编号函数作用
1del 列表[索引]删除列表中的某个元素
2pop()删除指定下标的数据(默认为最后一个),并返回该数据
3remove()移除列表中某个数据的第一个匹配项。
4clear()清空列表,删除列表中的所有元素,返回空列表。

判断列表是否为空的方法

方式一:

list_temp = []
if len(list_temp):
    # 存在值即为真
else:
    # list_temp是空的

方式二:

list_temp = []
if list_temp:
    # 存在值即为真
else:
    # list_temp是空的

以上两种方法均可以判断出 list_temp 列表是否是空列表,第二个方法要优于第一个方法,在Python中,False,0,‘’,[],{},()都可以视为假。

列表的索引下标

用索引来访问list中每一个位置的元素,记得索引是从0开始的,当索引超出了范围时,Python会报一个IndexError错误,所以,要确保索引不要越界,记得最后一个元素的索引是len(classmates) - 1。

>>> list1 = [1, 2, 3, 'Marry']
>>> list1[len(list1) - 1]
'Marry'

如果要取最后一个元素,除了计算索引位置外,还可以直接用-1做索引,直接获取最后一个元素,以此类推,可以获取倒数第2个、倒数第3个。

>>> list1 = [1, 2, 3, 'Marry']
>>> list[-1]
list[-1]
>>> list[-2]
list[-2]

列表中元素的追加、插入、删除方法

使用append方法在列表的最后追加元素:

>>> list1.append('Lili')
>>> list1
[1, 2, 3, 'Marry', 'Lili']

使用insert方法可以把元素插入到指定的位置,比如索引号为1的位置:

>>> list1.insert(1, 'Jack')
>>> list1
[1, 'Jack', 2, 3, 'Marry', 'Lili']
>>>

使用pop()方法删除list末尾的元素:

>>> list1.pop()
'Lili'
>>> list1
[1, 'Jack', 2, 3, 'Marry']
>>>

要删除指定位置的元素,用pop(i)方法,其中i是索引位置:

>>> list1.pop(1)
'Jack'
>>> list1
[1, 2, 3, 'Marry']

要把某个元素替换成别的元素,可以直接赋值给对应的索引位置:

>>> list1[1] = 'Joseph'
>>> list1
[1, 'Joseph', 3, 'Marry']

列表中的元素可以是另一个列表,如果想取出嵌套列表中的c元素,可以这样:

>>> list1.append(['a', 'b', 'c', 'd', 'e'])
>>> list1
[1, 'Joseph', 3, 'Marry', ['a', 'b', 'c', 'd', 'e']]
>>> list1[4][2]
'c'

元组

元组的基本语法

# 多个数据元组
tuple1 = (10, 20, 30)

# 单个数据元组
tuple2 = (10,)

注意:如果定义的元组只有1个元素,后面也要加上“逗号”,因为如果不加的话,python规则中会认为这是一个计算公式,tuple2 = (10)的结果还是10,这是有歧义的,所以定义元祖中只有1个元素的时候,后面也要加上“逗号”。
元组和列表最大的区别是元组是不可变数据类型,所以元组没有append、insert、pop方法,也不能给元组中的某个元素赋值。
不可变的tuple有什么意义?因为tuple不可变,所以代码更安全。如果可能,能用tuple代替list就尽量用tuple。
tuple的陷阱:当你定义一个tuple时,在定义的时候,tuple的元素就必须被确定下来。
最后来看一个“可变的”tuple

>>> tuple1 = (1, 2, 3, 4, 5, 6, ['a', 'b', 'c', 'd'])
>>> tuple1[6][0] = 'Jack'
>>> tuple1
(1, 2, 3, 4, 5, 6, ['Jack', 'b', 'c', 'd'])

上面这个案例中,这个tuple1定义的时候有7个元素,分别是1, 2, 3, 4, 5, 6和一个list。表面上看,tuple的元素确实变了,但其实变的不是tuple的元素,而是list的元素。tuple一开始指向的list并没有改成别的list,所以,tuple所谓的“不变”是说,tuple的每个元素,指向永远不变。即指向’a’,就不能改成指向’b’,指向一个list,就不能改成指向其他对象,但指向的这个list本身是可变的!【回忆内存中变量和值的指向关系】

字典

字典是用大括号括起来的,里面是key:value键值对的方式存储起来的字典数据。
把数据放入dict的方法,除了初始化时指定外,还可以通过key放入:

>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
>>> d['Michael']
95
>>> d['Jack'] = 88
>>> d['Jack']
88

如果key不存在,dict就会报错,要避免key不存在的错误,有两种办法,一是通过in判断key是否存在:

>>> 'Thomas' in d
False

二是通过dict提供的get()方法,如果key不存在,可以返回None,或者自己指定的value,这里需要注意的是给一个不存在的key指定value时,并没有真正在字典中插入这个key和value:

>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
>>> d.get('Jack', -1)
-1
>>> d
{'Michael': 95, 'Bob': 75, 'Tracy': 85}

遍历字典数据和items方法

>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> for key in d:
...     print(key)
...
a
c
b

因为dict的存储不是按照list的方式顺序排列,所以,迭代(也就是遍历)出的结果顺序很可能不一样。

默认情况下,dict迭代的是key。如果要迭代value,可以用for value in d.values(),如果要同时迭代key和value,可以用for k, v in d.items()

# 1、定义一个字典
person = {'name':'貂蝉', 'age':18, 'mobile':'13765022249'}
# 2、调用items方法获取数据,得到返回结果:dict_items([('name', '貂蝉'), ('age', 18), ('mobile', '13765022249')])
print(person.items())
# 3、结合for循环对字典中的数据进行遍历
for key, value in person.items():
    print(f'{key}{value}')

字典与列表的区别

请务必注意,dict内部存放的顺序和key放入的顺序是没有关系的。

  • 和list比较,dict有以下几个特点
    1、查找和插入的速度极快,不会随着key的增加而变慢;
    2、需要占用大量的内存,内存浪费多。
  • 而list相反
    1、查找和插入的时间随着元素的增加而增加;
    2、占用空间小,浪费内存很少。

所以,dict是用空间来换取时间的一种方法
dict可以用在需要高速查找的很多地方,在Python代码中几乎无处不在,正确使用dict非常重要,需要牢记的第一条就是dict的key必须是不可变对象。
这是因为dict根据key来计算value的存储位置,如果每次计算相同的key得出的结果不同,那dict内部就完全混乱了。这个通过key计算位置的算法称为哈希算法(Hash)。
要保证hash的正确性,作为key的对象就不能变。在Python中,字符串、整数等都是不可变的,因此,可以放心地作为key。而list是可变的,就不能作为key:

>>> key = [1, 2, 3]
>>> d[key] = 'a list'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

集合

集合可以直接定义,也可以使用set方法把元素传给集合,这样操作:

>>> set1 = {1, 2, 3, 4, 5, '张三', '李四'}
>>> set1
{1, 2, 3, 4, 5, '张三', '李四'}
>>> set2 = set([4, 5, 6, 7, 8, 8])
>>> set2
{4, 5, 6, 7, 8}

注意,set2传入的参数[4, 5, 6, 7, 8, 8]是一个list,而显示的{4, 5, 6, 7, 8}只是告诉你这个set2内部有4, 5, 6, 7, 8这6个元素,显示的顺序也不表示set是有序的。重复元素在set中会自动被过滤。
通过add(key)方法可以添加元素到set中,可以重复添加,但不会有效果:

>>> set2.add(9)
>>> set2
{4, 5, 6, 7, 8, 9}
>>> set2.add(9)
>>> set2
{4, 5, 6, 7, 8, 9}

集合的三种删方法

① remove()方法:删除集合中的指定数据,如果数据不存在则报错。
② discard()方法:删除集合中的指定数据,如果数据不存在也不会报错。
③ pop()方法:随机删除集合中的某个数据,并返回这个数据。

# 1、定义一个集合
products = {'萝卜', '白菜', '水蜜桃', '奥利奥', '西红柿', '凤梨'}
# 2、使用remove方法删除白菜这个元素
products.remove('白菜')
print(products)
# 3、使用discard方法删除未知元素
products.discard('玉米')
print(products)
# 4、使用pop方法随机删除某个元素
del_product = products.pop()
print(del_product)

求交集、并集、差集

求集合的交集、并集、差集,分别用& | -来表示

# 求集合中的交集、并集、差集
s1 = {'刘备', '关羽', '张飞', '貂蝉'}
s2 = {'袁绍', '吕布', '曹操', '貂蝉'}

# 求两个集合中的交集
print(s1 & s2)

# 求两个集合中的并集
print(s1 | s2)

# 求连个集合中的差集
print(s1 - s2)
print(s2 - s1)

集合与字典的区别

set和dict的唯一区别仅在于没有存储对应的value,但是,set的原理和dict一样,所以,同样不可以放入可变对象,因为无法判断两个可变对象是否相等,也就无法保证set内部“不会有重复元素”。试试把list放入set,同样也会报错。

>>> set3 = {[1, 2, 3], 2}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

针对不可变对象的补充说明

str是不变对象,而list是可变对象。

对于可变对象,比如list,对list进行操作,list内部的内容是会变化的,比如:

>>> a = ['c', 'b', 'a']
>>> a.sort()	#sort方法是对列表进行重新排序
>>> a
['a', 'b', 'c']

而对于不可变对象,比如str,对str进行操作呢:

>>> a = 'abc'
>>> a.replace('a', 'A')
'Abc'
>>> a
'abc'

虽然字符串有个replace()方法,也确实变出了’Abc’,但变量a最后仍是’abc’,应该怎么理解呢?
我们先把代码改成下面这样:

>>> a = 'abc'
>>> b = a.replace('a', 'A')	#replace方法将小a 替换成 A
>>> b
'Abc'
>>> a
'abc'

要始终牢记的是,a是变量,而'abc'才是字符串对象!有些时候,我们经常说,对象a的内容是'abc',但其实是指,a本身是一个变量,它指向的对象的内容才是'abc'
在这里插入图片描述

当我们调用a.replace('a', 'A')时,实际上调用方法replace是作用在字符串对象'abc'上的,而这个方法虽然名字叫replace,但却没有改变字符串'abc'的内容。相反,replace方法创建了一个新字符串'Abc'并返回,如果我们用变量b指向该新字符串,就容易理解了,变量a仍指向原有的字符串'abc',但变量b却指向新字符串'Abc'了。
在这里插入图片描述
所以,对于不变对象来说,调用对象自身的任意方法,也不会改变该对象自身的内容。相反,这些方法会创建新的对象并返回,这样,就保证了不可变对象本身永远是不可变的。

数据序列的公共方法

公共方法1

运算符描述支持的容器类型
+合并字符串、列表、元组
*复制字符串、列表、元组
in元素是否存在字符串、列表、元组、字典
not in元素是否不存在字符串、列表、元组、字典

公共方法2

编号函数描述
1len()计算容器中元素个数
2del或del()根据索引下标删除指定元素
3max()返回容器中元素最大值
4min()返回容器中元素最小值
5range(start, end, step)生成从start到end(不包含)的数字,步长为 step,供for循环使用
6enumerate()函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。

推导式

列表推导式

基本语法

变量名 = [表达式 for 变量 in 列表 for 变量 in 列表]
变量名 = [表达式 for 变量 in 列表 if 条件]

案例1:定义0-9之间的列表

list1 = [i for i in range(10)]
print(list1)

案例2:生成0-9之间的偶数(i%2 == 0)序列

list1 = [i for i in range(10) if i % 2 == 0]
print(list1)

案例3:创建列表 => [(1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

list1 = [(i, j) for i in range(1, 3) for j in range(0, 3)]
print(list1)

字典推导式

字典推导式作用:快速合并列表为字典或提取字典中目标数据。
基本语法

变量 = {key:value for key,value in 序列}

案例1:创建一个字典:字典key是1-5数字,value是这个数字的2次方。

dict1 = {i:i**2 for i in range(1,6)}
print(dict1)

案例2:把两个列表合并为一个字典

list1 = ['name', 'age', 'gender']
list2 = ['Tom', 20, 'male']
# 结果:person = {'name':'Tom', 'age':20, 'gender':'male'}

person = {list1[i]:list2[i] for i in range(len(list1))}
print(person)

案例3:提取字典中目标数据

counts = {'MBP': 268, 'HP': 125, 'DELL': 201, 'Lenovo': 199, 'ACER': 99}

# 需求:提取上述电脑数量大于等于200的字典数据
counts = {key:value for key, value in counts.items() if value >= 200}
print(counts)

集合推导式

集合推导式跟列表推导式非常相似,唯一区别在于用 { } 代替 [ ]。
集合推导式的作用:集合的最大特点就是去重
案例:创建一个集合,数据为下方列表的2次方。
list1 = [1, 1, 2]
set1 = {1, 4}

list1 = [1, 1, 2]
set1 = {i**2 for i in list1}
print(set1)

if else判断

if <条件判断1>:
    <执行1>
elif <条件判断2>:
    <执行2>
elif <条件判断3>:
    <执行3>
else:
    <执行4>

条件判断可以让计算机自己做选择,Python的if…elif…else很灵活。
条件判断从上向下匹配,当满足条件时执行对应的块内语句,后续的elif和else都不再执行。
案例:
小明身高1.75,体重80.5kg。请根据BMI公式(体重除以身高的平方)帮小明计算他的BMI指数,并根据BMI指数:

低于18.5:过轻
18.5-25:正常
25-28:过重
28-32:肥胖
高于32:严重肥胖

height = 1.75
weight = 80.5
bmi = weight / height**2
if bmi <= 18.5:
    print(f'{bmi}过轻')
elif bmi <= 25:
    print(f'{bmi}正常')
elif bmi <= 32:
    print(f'{bmi}肥胖')
else:
    print(f'{bmi}严重肥胖')

循环

while循环

while循环,只要条件满足,就不断循环,条件不满足时退出循环。比如我们要计算100以内所有奇数之和,可以用while循环实现:

a = 1
sum = 0
while a <= 99:
    sum += a
    a += 2
print(sum)

break和continue

break语句和continue语句的区别在于,break语句将终止整个循环语句,而continue语句只结束本次循环,这两个语句通常配合if语句使用。
例如利用if条件判断,continue可以跳过某些符合条件的操作,例如“打印出1~10。但是,如果我们想只打印奇数”:

n = 0
while n < 10:
    n = n + 1
    if n % 2 == 0: # 如果n是偶数,执行continue语句
        continue # continue语句会直接继续下一轮循环,后续的print()语句不会执行
    print(n)

for循环

for x in …循环就是把每个元素代入变量x,然后执行缩进块的语句。例如:

L = ['Bart', 'Lisa', 'Adam']
for i in L:
    print(f'{i},hello!')
#输出结果如下:
Bart,hello!
Lisa,hello!
Adam,hello!

可以使用range(101)方法生成1-100的序列,再通过list()函数可以转换为list。比如range(5)生成的序列是从0开始小于5的整数。如果要计算1-100的整数之和,那就是:

sum = 0
for x in range(101):
    sum = sum + x
print(sum)

迭代器

我们已经知道,可以直接作用于for循环的数据类型有以下几种:
一类是集合数据类型,如listtupledictsetstr等;
一类是generator,包括生成器和带yieldgenerator function
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

可以使用isinstance()判断一个对象是否是Iterable对象:

>>> from collections.abc import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
可以使用isinstance()判断一个对象是否是Iterator对象:

>>> from collections.abc import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False

生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator
listdictstrIterable变成Iterator可以使用iter()函数:

>>> from collections.abc import Iterator
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

你可能会问,为什么listdictstr等数据类型不是Iterator
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
Python的for循环本质上就是通过不断调用next()函数实现的,例如:

for x in [1, 2, 3, 4, 5]:
    pass

实际上完全等价于:

# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
    try:
        # 获得下一个值:
        x = next(it)
    except StopIteration:
        # 遇到StopIteration就退出循环
        break

函数相关

内置函数

函数功能
abs()把传入的值转换为绝对值
int()把传入的值转换为整型
max(a, b, c……)输出最大值
float()把传入的值转换为浮点数
str()把传入的值转换为字符串
bool()把传入的值转换为布尔类型
hex()把一个整数转换成十六进制表示的字符串
type()输出括号内数据的数据类型
isinstance(x, (类型1, 类型2))数据类型检查
enumerate([list])可以把一个list变成索引-元素对
字符串.lower()把字符串所有的字符变成小写

函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”:

>>> a = abs # 变量a指向abs函数
>>> a(-1) # 所以也可以通过a调用abs函数
1

请注意,函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。因此,函数内部通过条件判断和循环可以实现非常复杂的逻辑。

如果没有return语句,函数执行完毕后也会返回结果,只是结果为None。return None可以简写为return。
函数可以同时返回多个值,但其实就是一个tuple。在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数返回多值其实就是返回一个tuple,但写起来更方便。

空函数

如果想定义一个什么事也不做的空函数,可以用pass语句:

def nop():
    pass

pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。

函数的形参和实参

形参:在函数定义时,所编写的参数就称之为形式参数
实参:在函数调用时,所传递的参数就称之为实际参数

def greet(name):  # name就是在函数greet定义时,所编写的参数(形参)
    return name + ',您好'

# 调用函数
name = '老王'
greet(name)  # 在函数调用时,所传递的参数就是实际参数

注意:虽然我们在函数传递时,喜欢使用相同的名称作为参数名称。但是两者的作用范围是不同的。name = ‘老王’,代表实参。其是一个全局变量,而greet(name)函数中的name实际是在函数定义时才声明的变量,所以其实一个局部变量。

函数的参数传递两种方式

位置参数传递方式:理论上,在函数定义时,我们可以为其定义多个参数。但是在函数调用时,我们也应该传递多个参数,正常情况,其要一一对应。

def user_info(name, age, address):
    print(f'我的名字{name},今年{age}岁了,家里住在{address}')
    
# 调用函数
user_info('Tom', 23, '美国纽约')

关键词参数传递方式:函数调用,通过“键=值”形式加以指定。可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求。

def user_info(name, age, address):
    print(f'我的名字{name},今年{age}岁了,家里住在{address}')
    
# 调用函数(使用关键词参数)
user_info(name='Tom', age=23, address='美国纽约')

函数定义时的缺省参数

缺省参数也叫默认参数,用于定义函数,为参数提供默认值,调用函数时可不传该默认参数的值(注意:所有位置参数必须出现在默认参数前,包括函数定义和调用)。

def user_info(name, age, gender='男'):
    print(f'我的名字{name},今年{age}岁了,我的性别为{gender}')

user_info('李林', 25)
user_info('振华', 28)
user_info('婉儿', 18, '女')

函数传递参数的补充说明

在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。
但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

比如定义一个函数,包含上述若干种参数:

def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

在函数调用的时候,Python解释器自动按照参数位置和参数名把对应的参数传进去。

>>> f1(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
>>> f1(1, 2, c=3)
a = 1 b = 2 c = 3 args = () kw = {}
>>> f1(1, 2, 3, 'a', 'b')
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
>>> f1(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
>>> f2(1, 2, d=99, ext=None)
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}

最神奇的是通过一个tuple和dict,你也可以调用上述函数:

>>> args = (1, 2, 3, 4)
>>> kw = {'d': 99, 'x': '#'}
>>> f1(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
>>> args = (1, 2, 3)
>>> kw = {'d': 88, 'x': '#'}
>>> f2(*args, **kw)
a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}

参考廖雪峰的“函数的参数”章节,讲的非常细致:https://www.liaoxuefeng.com/wiki/1016959663602400/1017261630425888

global关键字

global关键字,是用来解决多函数数据共享以及全局变量修改问题,格式:
在def函数体内:global 函数名

# 定义全局变量num = 10
num = 10
# 定义一个函数func
def func():
    # 尝试在局部作用域中修改全局变量
    global num
    num = 20

# 调用函数func
func()
# 尝试访问全局变量num
print(num)

函数的递推与递归

递推

递归算法:递推算法是一种简单的算法,即通过已知条件,利用特定条件得出中间推论,直至得到结果的算法。递推又分为顺推和逆推。
顺推:通过最简单的条件,然后逐步推演结果
逆推:通过结果找到规律,然后推导已知条件
案例:求斐波那契数列
1 1 2 3 5 8 13 21 …
① ② ③ ④ ⑤ ⑥ …

第1位为1,第2位为1,第3位为2 = 1 + 1,第4位为3 = 2 + 1,依次类推…第n位结果为多少?
f(n) = f(n-1) + f(n-2)

提出问题:求斐波那契数列第15位的结果?
分析: f(15) = f(14) + f(13)
​ f(14) = f(13) + f(12)
​ f(13) = f(12) + f(11)
​ …
​ f(4) = f(3) + f(2) = 3 + 1
​ f(3) = f(2) + f(1) = 2
​ f(2) = 1
​ f(1) = 1
递推算法:使用while循环或for循环

# 递推算法:根据已知条件,求结果(或者根据结果求未知条件)
def recusive(n):
    """ 返回斐波那契数列某一位(n>=1)的结果 """
    if n == 1 or n == 2:
        return 1
    # 开始递推f(3) = f(2) + f(1)  f(4) = f(3) + f(2) ... f(15) = f(14) + f(13)
    dict1 = {1:1, 2:1}
    for i in range(3, n+1):
        # f(3) = f(2) + f(1)
        # f(i) = f(i-1) + f(i-2)
        dict1[i] = dict1[i-1] + dict1[i-2]
    return dict1[n]

# 函数调用
print(recusive(15))
递归

① 明确你这个函数想要干什么
如:求斐波那契数列

② 寻找递归结束条件
如:就是在什么情况下,递归会停止循环,返回结果

③ 找出函数的等价关系式
如:斐波那契数列,第n位 f(n) = f(n-1) + f(n-2)

案例1:使用递归求斐波那契数列
第一步:明确这个函数想要干什么(先定义出来,明确调用方式)

# 斐波那契数列 1 1 2 3 5 8 13 21 ...
def f(n):
    # 编写递归代码求第n位的结果

# 调用函数
print(f(15))  # 610

第二步:寻找递归的结束条件

# 斐波那契数列 1 1 2 3 5 8 13 21 ...
def f(n):
    # 编写递归代码求第n位的结果
    if n == 1 or n == 2:
        return 1

# 调用函数
print(f(15))  # 610

第三步:找出函数的等价关系式(最关键的一步)

# 斐波那契数列 1 1 2 3 5 8 13 21 ...
def f(n):
    # 编写递归代码求第n位的结果
    if n == 1 or n == 2:
        return 1
    # 找出与斐波那契数列等价的关系式
    return f(n-1) + f(n-2)

# 调用函数
print(f(15))  # 610

案例2:使用递归求N的阶乘(如n=100)
阶乘是什么?一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,如:n!=1×2×3×…×(n-1)×n
1! = 1
2! = 1x2 = 2
3! = 1x2x3 = 6
4! = 1x2x3x4 = 24

n!=1×2×3×…×(n-1)×n

第一步:明确这个函数要做什么以及定义函数以及调用方式

def f(n):
    # 编写递归条件
    
print(f(100))

第二步:寻找递归的结束条件

def f(n):
    # 编写递归结束条件
    if n <= 2:
        return n
    # ...递归等式
print(f(100))

第三步:编写递归等价公式(自己要调用自己)
等价公式 = 找规律
1! = f(1) = 1
2! = f(2) = 2
3! = f(2)x3 = 6
4! = f(3)x4 = 24

n!= f(n-1) * n

def f(n):
    # 编写递归结束条件
    if n <= 2:
        return n
    # ...递归等式
    return f(n-1) * n
print(f(100))

案例3:面试题 => 猴子吃桃问题
猴子吃桃问题。猴子第1天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第2天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半另加一个。到第10天早上想再吃时,就只剩下一个桃子了。求第1天共摘了多少个桃子

第一步:确定函数主要要完成什么功能,需要传递哪些参数,确认调用方式

def f(n):
    # 编写递归代码
    
# 调用f函数
print(f(1))

第二步:编写递归的结束条件(出口)

# 第一步:确定函数功能
def f(n):
    # 第二步:编写递归结束条件(出口)
    if n == 10:
        return 1

# 调用函数
print(f(1))

第三步:找出与这个问题相等的等式关系

求桃子的剩余数量?假设法:假设有10个桃子

第1天,10个桃子吃一半,10/2 = 5 + 1 = 6

第2天,4个桃子吃一半,4/2 = 2 + 1 = 3

第3天,再想吃剩1个

第n天,总剩余桃子的数量 = (第(n+1)天桃子的剩余桃子的数量 + 1) * 2

# 第一步:确定函数功能
def f(n):
    # 第二步:编写递归结束条件(出口)
    if n == 10:
        return 1
    # 第三步:寻找与这个问题相似的等价公式
    return (f(n+1) + 1) * 2

# 调用函数
print(f(8))

lambda表达式

如果一个函数有一个返回值,并且只有一句代码,可以使用 lambda简化,Lambda函数,是一个匿名函数。
语法:
lambda parameters:express
parameters:可选,如果提供,通常是逗号分隔的变量表达式形式,即位置参数。
expression:不能包含分支或循环(但允许条件表达式),也不能包含return(或yield)函数。如果为元组,则应用圆括号将其包含起来。
调用lambda函数,返回的结果是对表达式计算产生的结果。
案例1:定义一个函数,最终返回100

fn2 = lambda : 100

print(fn2)  # 返回fn2在内存中的地址
print(fn2())

案例2:编写一个函数求两个数的和

fn2 = lambda num1, num2:num1 + num2

print(fn2(10, 20))
用lambda进行排序

1)单一列表:(其实可以直接使用sorted函数实现)
在这里插入图片描述
2)列表中嵌套字典
在这里插入图片描述
3)列表嵌套列表,且根据2个字段进行排序
在这里插入图片描述

高阶函数

函数作为参数传入,这样的函数称为高阶函数,高阶函数是函数式编程的体现。函数式编程就是指这种高度抽象的编程范式。
大多数作为参数传入函数的函数,都是python内置的函数。

案例:任意两个数字,按照指定要求(① 绝对值 ② 四舍五入)整理数字后再进行求和计算。

def fn(num1, num2, f):
    # f代表要传入的参数(参数是一个函数名,如abs或round)
    return f(num1) + f(num2)

# 绝对值求和
print(fn(-10, 10, abs))
# 四舍五入
print(fn(10.2, 6.9, round))
map()函数

map(func, lst),将传入的函数变量func作用到lst变量的每个元素中,并将结果组成新的列表(Python2)/迭代器(Python3)返回。

# 定义一个函数
def func(n):
    return n ** 2
# 定义一个列表
list1 = [1, 2, 3]
# 使用map对lst进行func函数操作
list2 = list(map(func, list1))
print(list2)
reduce()函数

reduce(func,lst),其中func必须有两个参数。每次func计算的结果继续和序列的下一个元素做累加计算。> 注意:reduce()传入的参数func必须接收2个参数。

import functools


# 定义一个函数
def func(a, b):
    return a + b
# 定义一个列表
list1 = [10, 20, 30, 40, 50]
sums = functools.reduce(func, list1)
print(sums)
filter()函数

filter(func, lst)函数用于过滤序列, 过滤掉不符合条件的元素, 返回一个 filter 对象。如果要转换为列表, 可以使用 list() 来转换。

# 定义一个函数(获取所有的偶数)
def func(n):
   return n % 2 == 0
# 定义一个序列
list1 = [1, 2, 3, 4, 5, 6, 7, 8]
# 调用filter函数进行过滤操作
result = filter(func, list1)
print(list(result))

Python拆包

Python拆包:就是把元组或字典中的数据单独的拆分出来,然后赋予给其他的变量。

元组拆包

def func():
    # 经过一系列操作返回一个元组
    return 100, 200	 # tuple元组类型的数据

# 定义两个变量接收元组中的每个数组(拆包)
num1, num2 = func()
# 打印num1和num2
print(num1)
print(num2)

字典拆包

dict1 = {'name':'小明', 'age':18}
# 拆包的过程(字典)
a, b = dict1
print(a)
print(b)
# 获取字典中的数据
print(dict1[a])
print(dict1[b])

拆包案例

题目:已知C1=10和C2=2,交换C1和C2两个变量的值。
方法一:引入临时变量

c1 = 10
c2 = 2

# 引入临时变量temp
temp = c2
c2 = c1
c1 = temp

print(c1, c2)

方法二:面试官经常考的:使用加法与减法运算交换两个变量的值(不需要引入临时变量)
口诀:C1加、C2减、C1再去减

c1 = 10
c2 = 2

c1 = c1 + c2
c2 = c1 - c2
c1 = c1 - c2

print(c1, c2)

方法三:只有Python才具有的特性,拆包方法。

c1 = 10
c2 = 2

c1, c2 = c2, c1 # 实际这步是c1, c2 = (c2, c1),就是把C2和C1放到元组中,再拆包分别赋值给C1和C2
print(c1, c2)

文件的操作

seek函数移动光标

r --> 文件头
w --> 清空文件内容,指向文件头
a -->文件尾

光标在打开文件时,默认情况下是根据r、w、a模式相关固定的,但是我们可以通过某些方法,人为移动光标,可以通过seek方法实现。
实际工作中,seek主要用于重置光标到起始位置。

f.seek(0)
或
f.seek(0, 0)

其他应用:

>>> f = open('workfile', 'rb+')
>>> f.write(b'0123456789abcdef')
16
>>> f.seek(5)      # 从0开始向右移动5个字节
5
>>> f.read(1)
b'5'
>>> f.seek(-3, 2)  # 从右向左移动3个字节
13
>>> f.read(1)
b'd'

文件备份

Python的高级特性

切片

列表list、元组tuple、字符串str均可以用切片方法,切片的完整方法是[::],第一个冒号前面代表切片起始位置(默认是下标0),第一个冒号后面代表结束切片位置(默认是最后一个元素的下标),第二个冒号后面代表步长(默认是1),记住一个切片口诀“只顾头来不顾尾”,例如从下标0切片到下标3,那么切除来的数据就是下标012的数据序列,不包括3。
提取某一个元素,直接[下标值]即可。以下是一些示例:

>>> L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
>>>> L[:]	#复制了L列表
['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
>>> L[::2]	#步长为2进行切片
['Michael', 'Tracy', 'Jack']
>>> L[:3]	#从默认的索引下标0到下标为3进行切片(不包含下标3)
['Michael', 'Sarah', 'Tracy']
>>> L[1:3]	#从默认的索引下标1到下标3进行切片(不包含下标3)
['Sarah', 'Tracy']
>>> L[-1]	#只切出最后一个元素,最后一个元素就是-1,依次往左是-2, -3, -4 ……
'Jack'
>>> L[:-1]	#从默认的索引下标0到下标为-1进行切片(不包含下标-1)
['Michael', 'Sarah', 'Tracy', 'Bob']


各种报错提示

报错提示报错类型可能的原因
SyntaxError表示输入的Python代码有语法错误常见的是使用了中文标点符号如括号、引号

各种案例

格式化字符串案例

小明的成绩从去年的72分提升到了今年的85分,请计算小明成绩提升的百分点,并用字符串格式化显示出’xx.x%',只保留小数点后1位。

a = 72
b = 85
print('%.2f%%' % (((b -a) / a) * 100))
#得到的结果是18.06%

编写一个求绝对值的函数

不用abs()内置函数,手动编写一个求绝对值的自定义函数。

def my_abs(num):
	num = int(num)
	if num >= 0:
		return num
	else:
		return -num
		
input_num = input('请输入一个数字:')
print(f'{input_num}的绝对值是{my_abs(input_num)}')

扩展:
但是如果参数类型不对,Python解释器就无法帮我们检查。试试my_abs和内置函数abs的差别:

>>> my_abs('A')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in my_abs
TypeError: unorderable types: str() >= int()
>>> abs('A')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bad operand type for abs(): 'str'

当传入了不恰当的参数时,内置函数abs会检查出参数错误,而我们定义的my_abs没有参数检查,会导致if语句出错,出错信息和abs不一样。所以,这个函数定义不够完善。
让我们修改一下my_abs的定义,对参数类型做检查,只允许整数和浮点数类型的参数。数据类型检查可以用内置函数isinstance()实现:

def my_abs(num):
	if not isinstance(num, (float, int))raise TypeError('必须输入整数或小数')
	if num >= 0:
		return num
	else:
		return -num
		
input_num = input('请输入一个数字:')
print(f'{input_num}的绝对值是{my_abs(input_num)}')

一元二次方程求解

请定义一个函数quadratic(a, b, c),接收3个参数,返回一元二次方程 a x 2 + b x + c = 0 ax^2+bx+c=0 ax2+bx+c=0的两个解。

提示:

一元二次方程的求根公式为:
x = − b ± b 2 − 4 a c 2 a x=\frac{-b\pm\sqrt{b^2-4ac}}{2a} x=2ab±b24ac

import math
def quadratic(a, b, c):
    x1 = (-b + math.sqrt((b * b) - (4 * a * c))) / (2 * a)
    x2 = (-b - math.sqrt((b * b) - (4 * a * c))) / (2 * a)
    return x1, x2

a = int(input('请输入a的值:'))
b = int(input('请输入b的值:'))
c = int(input('请输入c的值:'))
print(quadratic(a, b, c))

函数传参案例

以下函数允许计算两个数的乘积,请稍加改造,变成可接收一个或多个数并计算乘积:

def mul(x, y):
    return x * y

改造后的正确代码:

def mul(n1, *args):
    s = 1
    for x in args:
        s = s * x
    return s * n1
# 测试
print('mul(5) =', mul(5))
print('mul(5, 6) =', mul(5, 6))
print('mul(5, 6, 7) =', mul(5, 6, 7))
print('mul(5, 6, 7, 9) =', mul(5, 6, 7, 9))
if mul(5) != 5:
    print('测试失败!')
elif mul(5, 6) != 30:
    print('测试失败!')
elif mul(5, 6, 7) != 210:
    print('测试失败!')
elif mul(5, 6, 7, 9) != 1890:
    print('测试失败!')
else:
    try:
        mul()
        print('测试失败!')
    except TypeError:
        print('测试成功!')

需要注意的是,为什么前面需要一个位置参数n1,因为函数中*args默认为(),调用时若未输入参数即输入()时无法通过最后的异常处理测试,所以必须要加1个位置参数n1.

切片案例题

利用切片操作,实现一个trim()函数,去除字符串首尾的空格,注意不要调用str的strip()方法:

def trim(s):
    while s[-1:] == ' ':
        s = s[:-1]
    while s[:1] == ' ':
        s = s[1:]
    return s

if trim('hello  ') != 'hello':
    print('测试失败!')
elif trim('  hello') != 'hello':
    print('测试失败!')
elif trim('  hello  ') != 'hello':
    print('测试失败!')
elif trim('  hello  world  ') != 'hello  world':
    print('测试失败!')
elif trim('') != '':
    print('测试失败!')
elif trim('    ') != '':
    print('测试失败!')
else:
    print('测试成功!')


#
# while True:
#     s = input('请输入一个字符串:')
#     if len(s) == 0:
#         print('您没有输入任何字符!')
#         continue
#     else:
#         break
# news = trim(s)
# print(news, len(news))

迭代案例

不用min和max内置方法,而请使用迭代方法,查找一个list中最小和最大值,并返回一个tuple:

def findMinAndMax(L):
    if len(L) == 0:
        return (None, None)
    else:
        min = L[0]
        max = L[0]
        for number in L:
            if min >= number:
                min = number
            if max <= number:
                max = number
        return (min, max)

# 测试
if findMinAndMax([]) != (None, None):
    print('测试失败!')
elif findMinAndMax([7]) != (7, 7):
    print('测试失败!')
elif findMinAndMax([7, 1]) != (1, 7):
    print('测试失败!')
elif findMinAndMax([7, 1, 3, 9, 5]) != (1, 9):
    print('测试失败!')
else:
    print('测试成功!')

列表推导式案例

如果list中既包含字符串,又包含整数,由于非字符串类型没有lower()方法,使用内建的isinstance函数可以判断一个变量是不是字符串,请修改列表生成式,通过添加if语句保证列表生成式能正确地执行:

>>> L = ['Hello', 'World', 18, 'Apple', None]
>>> [s.lower() for s in L if isinstance(s, str)]
['hello', 'world', 'apple']

map()函数案例

利用map()函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。输入:[‘adam’, ‘LISA’, ‘barT’],输出:[‘Adam’, ‘Lisa’, ‘Bart’]:

def normalize(name):
    name = name[0].upper() + name[1:].lower()
    return name

# 测试:
L1 = ['adam', 'LISA', 'barT']
L2 = list(map(normalize, L1))
print(L2)

reduce()函数案例

Python提供的sum()函数可以接受一个list并求和,请编写一个prod()函数,可以接受一个list并利用reduce()求积:

from functools import reduce
def prod(L):
    return reduce(lambda x, y : x * y, L)

print('3 * 5 * 7 * 9 =', prod([3, 5, 7, 9]))
if prod([3, 5, 7, 9]) == 945:
    print('测试成功!')
else:
    print('测试失败!')

filter()函数案例

回数是指从左向右读和从右向左读都是一样的数,例如12321,909。请利用filter()筛选出回数:

#第一种
def is_palindrome(n):
    nn = str(n) # 转成字符串
    return nn == nn[::-1] #反转字符串并对比原字符串返回true/false
print (list(filter(is_palindrome,range(1000,1000000))))
 
#第二种
print (list(filter(lambda n : str(n)==str(n)[::-1],range(1,1000)))) #str(n)同上

sorted()方法案例

假设我们用一组tuple表示学生名字和成绩:

L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]

请用sorted()对上述列表分别按名字排序、再按成绩排序:

L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_name(t):
    return t[0]

def by_score(t):
    return t[1]

L2 = sorted(L, key=by_name)
print(L2)

L3 = sorted(L, key=by_score)
print(L3)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值