Python学习笔记
Python基础
命令行与交互模式的区别
在交互模式:在windows电脑的cmd下,输入python,即可进入交互模式,前面会有提示符>>>
,在提示符后面直接输入代码,按回车,就可以立刻得到代码执行结果。
命令行模式:执行一个.py文件只能在命令行模式执行。如敲一个命令python hello.py。
运算符
and运算是与运算,只有所有都为True,and运算结果才是True。
or运算是或运算,只要其中有一个为True,or运算结果就是True。
not运算是非运算,它是一个单目运算符,把True变成False,False变成True。
在Python交互模式下输入 210 你会得到:
运算符**
为幂 ,210就是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可以处理任意大小的整数,当然包括负整数,在程序中的表示方法和数学上的写法一模一样,例如:1
,100
,-8080
,0
,等等。
计算机由于使用二进制,所以,有时候用十六进制表示整数比较方便,十六进制用0x
前缀和0-9
,a-f
表示,例如:0xff00
,0xa5b4c3d2
,等等。
对于很大的数,例如10000000000
,很难数清楚0的个数。Python允许在数字中间以_分隔,因此,写成10_000_000_000
和10000000000
是完全一样的。十六进制数也可以写成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 | 字符串 |
%x | 16进制整数 |
- %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))
列表
列表的四种删方法
编号 | 函数 | 作用 |
---|---|---|
1 | del 列表[索引] | 删除列表中的某个元素 |
2 | pop() | 删除指定下标的数据(默认为最后一个),并返回该数据 |
3 | remove() | 移除列表中某个数据的第一个匹配项。 |
4 | clear() | 清空列表,删除列表中的所有元素,返回空列表。 |
判断列表是否为空的方法
方式一:
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
编号 | 函数 | 描述 |
---|---|---|
1 | len() | 计算容器中元素个数 |
2 | del或del() | 根据索引下标删除指定元素 |
3 | max() | 返回容器中元素最大值 |
4 | min() | 返回容器中元素最小值 |
5 | range(start, end, step) | 生成从start到end(不包含)的数字,步长为 step,供for循环使用 |
6 | enumerate() | 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 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循环的数据类型有以下几种:
一类是集合数据类型,如list
、tuple
、dict
、set
、str
等;
一类是generator
,包括生成器和带yield
的generator 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
对象,但list
、dict
、str
虽然是Iterable
,却不是Iterator
。
把list
、dict
、str
等Iterable
变成Iterator
可以使用iter()
函数:
>>> from collections.abc import Iterator
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
你可能会问,为什么list
、dict
、str
等数据类型不是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=2a−b±b2−4ac
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)