廖雪峰py教程
py基础
与C语言不同
缩进有语法含义
注释以
#
开头当语句以冒号
:
结尾时,缩进的语句视为代码块大小写敏感
补充
- 逻辑运算符
- 逻辑运算符
数据表示
- 对于很大的数,例如
10000000000
,很难数清楚0的个数。Python允许在数字中间以_
分隔,因此,写成10_000_000_000
和10000000000
是完全一样的。十六进制数也可以写成0xa1b2_c3d4
- 字符串用单引号
'
或双引号"
括起来,如果'
本身也是一个字符,那就要用""
括起来 - 转义字符与C语言相同,额外的是:如果字符串里面有很多字符都需要转义,就需要加很多
\
,为了简化,Python还允许用r''
表示''
内部的字符串默认不转义,如下例: - 在Python中,可以直接用
True
、False
表示布尔值(请注意大小写)
变量
python的变量类型不固定,称作动态语言,与之对应的是静态语言。静态语言在定义变量时必须指定变量类型,如果赋值的时候类型不匹配,就会报错
两种除法:
/
除法计算结果是浮点数,即使是两个整数恰好整除,结果也是浮点数1
29 / 3
3.0还有一种除法是
//
,称为地板除,两个整数的除法仍然是整数1
210 // 3
3
字符串
本节内容并未深究,详见网址编码部分
在最新的Python 3版本中,字符串是以Unicode编码的,也就是说,Python的字符串支持多语言
由于Python的字符串类型是
str
,在内存中以Unicode表示,一个字符对应若干个字节。如果要在网络上传输,或者保存到磁盘上,就需要把str
变为以字节为单位的bytes
。Python对
bytes
类型的数据用带b
前缀的单引号或双引号表示:1
x = b'ABC'
要注意区分
'ABC'
和b'ABC'
,前者是str
,后者虽然内容显示得和前者一样,但bytes
的每个字符都只占用一个字节要计算
str
包含多少个字符,可以用len()
函数:1
2
3
4len('ABC')
3
len('中文')
2len()
函数计算的是str
的字符数,如果换成bytes
,len()
函数就计算字节数:1
2
3
4
5
6len(b'ABC')
3
len(b'\xe4\xb8\xad\xe6\x96\x87')
6
len('中文'.encode('utf-8'))
6格式化字符串
在Python中,采用的格式化方式和C语言是一致的,用
%
实现,举例如下:1
2
3
4'Hello, %s' % 'world'
'Hello, world'
'Hi, %s, you have $%d.' % ('Michael', 1000000)
'Hi, Michael, you have $1000000.'格式见例子,占位符和C语言一样
普通%字符用
%%
来转义表示f-string
最后一种格式化字符串的方法是使用以
f
开头的字符串,称之为f-string
,它和普通字符串不同之处在于,字符串如果包含{xxx}
,就会以对应的变量替换:1
2
3
4>>> 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
list
Python内置的一种数据类型是列表:list。list是一种有序的集合,可以随时添加和删除其中的元素。
1 | 'Michael', 'Bob', 'Tracy'] classmates = [ |
变量classmates
就是一个list。用len()
函数可以获得list元素的个数:
1 | len(classmates) |
如果要取最后一个元素,除了计算索引位置外,还可以用
-1
做索引,直接获取最后一个元素以此类推,-2是倒数第二个元素,-3是倒数第三个元素
list是一个可变的有序表,所以,可以往list中追加元素到末尾:
1
2
3>>> classmates.append('Adam')
>>> classmates
['Michael', 'Bob', 'Tracy', 'Adam']也可以把元素插入到指定的位置,比如索引号为
1
的位置:1
2
3>>> classmates.insert(1, 'Jack')
>>> classmates
['Michael', 'Jack', 'Bob', 'Tracy', 'Adam']要删除list末尾的元素,用
pop()
方法:1
2
3
4>>> classmates.pop()
'Adam'
>>> classmates
['Michael', 'Jack', 'Bob', 'Tracy']要删除指定位置的元素,用
pop(i)
方法,其中i
是索引位置:1
2
3
4>>> classmates.pop(1)
'Jack'
>>> classmates
['Michael', 'Bob', 'Tracy']要把某个元素替换成别的元素,可以直接赋值给对应的索引位置:
1
2
3>>> classmates[1] = 'Sarah'
>>> classmates
['Michael', 'Sarah', 'Tracy']list元素也可以是另一个list,比如:
1
2
3>>> s = ['python', 'java', ['asp', 'php'], 'scheme']
>>> len(s)
4
tuple
另一种有序列表叫元组:tuple。tuple和list非常类似,但是tuple一旦初始化就不能修改,比如同样是列出同学的名字:注意使用圆括号括起来的,而list是方括号
1 | >>> classmates = ('Michael', 'Bob', 'Tracy') |
现在,classmates这个tuple不能变了,它也没有append(),insert()这样的方法。其他获取元素的方法和list是一样的,你可以正常地使用classmates[0]
,classmates[-1]
,但不能赋值成另外的元素。
不可变的tuple有什么意义?因为tuple不可变,所以代码更安全。如果可能,能用tuple代替list就尽量用tuple。
tuple在声明时必须初始化
a=(1)
时,括号内只有一个元素,与数学符号圆括号冲突,此时默认a=1所以,只有1个元素的tuple定义时必须加一个逗号
,
,来消除歧义:1
2
3>>> t = (1,)
>>> t
(1,)Python在显示只有1个元素的tuple时,也会加一个逗号
,
,以免你误解成数学计算意义上的括号。
其他
elif
是else if
的缩写,完全可以有多个elif
input()函数
1
2
3
4
5birth = input('birth: ')
if birth < 2000:
print('00前')
else:
print('00后')这里input使用错误,input返回的是str类型,而str无法和int型的2000比较
py提供
int()
函数来实现类型转换:从字符串转换到对应的整数但此时若输入非数字的字符串,如’abc’,int()函数就会报错
循环
for…in循环:
1
2
3names = ['Michael', 'Bob', 'Tracy']
for name in names:
print(name)再比如我们想计算1-10的整数之和,可以用一个
sum
变量做累加:1
2
3
4sum = 0
for x in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
sum = sum + x
print(sum)如果要计算1-100的整数之和,从1写到100有点困难,幸好Python提供一个
range()
函数,可以生成一个整数序列,再通过list()
函数可以转换为list。比如range(5)
生成的序列是从0开始小于5的整数:1
2>>> list(range(5))
[0, 1, 2, 3, 4]range(101)
就可以生成0-100的整数序列计算0-100
1
2
3
4sum = 0
for x in range(101):
sum = sum + x
print(sum)
字典
Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。
如果用dict实现,只需要一个“名字”-“成绩”的对照表,直接根据名字查找成绩,无论这个表有多大,查找速度都不会变慢。用Python写一个dict如下:
1
2
3>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
>>> d['Michael']
95键-值(key-value),如果key不存在,dict就会报错
要避免key不存在的错误,有两种办法,一是通过
in
判断key是否存在:1
2>>> 'Thomas' in d
False二是通过dict提供的
get()
方法,如果key不存在,可以返回None
,或者自己指定的value:1
2
3>>> d.get('Thomas')
>>> d.get('Thomas', -1)
-1注意:返回
None
的时候Python的交互环境不显示结果。dict牺牲了空间来换取时间,而list相反,查找耗时较高,但空间占用少
dict的算法是通过key计算位置,称为哈希算法(Hash)
要保证hash的正确性,作为key的对象就不能变。在Python中,字符串、整数等都是不可变的,因此,可以放心地作为key。而list是可变的,就不能作为key
再议不可变对象
上面我们讲了,str是不变对象,而list是可变对象。
对于可变对象,比如list,对list进行操作,list内部的内容是会变化的,比如:
1 | >>> a = ['c', 'b', 'a'] |
而对于不可变对象,比如str,对str进行操作呢:
1 | >>> a = 'abc' |
虽然字符串有个replace()
方法,也确实变出了'Abc'
,但变量a
最后仍是'abc'
,应该怎么理解呢?
我们先把代码改成下面这样:
1 | >>> a = 'abc' |
要始终牢记的是,a
是变量,而'abc'
才是字符串对象!有些时候,我们经常说,对象a
的内容是'abc'
,但其实是指,a
本身是一个变量,它指向的对象的内容才是'abc'
:
1 | ┌───┐ ┌───────┐ |
当我们调用a.replace('a', 'A')
时,实际上调用方法replace
是作用在字符串对象'abc'
上的,而这个方法虽然名字叫replace
,但却没有改变字符串'abc'
的内容。相反,**replace
方法创建了一个新字符串'Abc'
并返回**,如果我们用变量b
指向该新字符串,就容易理解了,变量a
仍指向原有的字符串'abc'
,但变量b
却指向新字符串'Abc'
了:
1 | ┌───┐ ┌───────┐ |
所以,对于不变对象来说,调用对象自身的任意方法,也不会改变该对象自身的内容。相反,这些方法会创建新的对象并返回,这样,就保证了不可变对象本身永远是不可变的。
函数
数据类型转换
Python内置的常用函数还包括数据类型转换函数,比如int()
函数可以把其他数据类型转换为整数:
1 | int('123') |
函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”:
1 | abs # 变量a指向abs函数 a = |
函数定义
在Python中,定义一个函数要使用def
语句,依次写出函数名、括号、括号中的参数和冒号:
,然后,在缩进块中编写函数体,函数的返回值用return
语句返回。
1 | def my_abs(x): |
空函数
如果想定义一个什么事也不做的空函数,可以用pass
语句:
1 | def nop(): |
pass
语句什么都不做,那有什么用?实际上pass
可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass
,让代码能运行起来。
pass
还可以用在其他语句里,比如:
1 | if age >= 18: |
缺少了pass
,代码运行就会有语法错误。
返回多个值
函数可以返回多个值吗?答案是肯定的。
比如在游戏中经常需要从一个点移动到另一个点,给出坐标、位移和角度,就可以计算出新的坐标:
1 | import math |
import math
语句表示导入math
包,并允许后续代码引用math
包里的sin
、cos
等函数。
然后,我们就可以同时获得返回值:
1 | >>> x, y = move(100, 100, 60, math.pi / 6) |
但其实这只是一种假象,Python函数返回的仍然是单一值:
1 | >>> r = move(100, 100, 60, math.pi / 6) |
原来返回值是一个tuple!但是,在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数返回多值其实就是返回一个tuple,但写起来更方便。
默认参数
1 | def enroll(name, gender, age=6, city='Beijing'): |
这样,大多数学生注册时不需要提供年龄和城市,只提供必须的两个参数:
1 | 'Sarah', 'F') enroll( |
只有与默认参数不符的学生才需要提供额外的信息:
1 | enroll('Bob', 'M', 7) |
可变参数
1 | def calc(*numbers): |
定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*
号。在函数内部,参数numbers
接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数:
1 | >>> calc(1, 2) |
如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做:
1 | >>> nums = [1, 2, 3] |
这种写法当然是可行的,问题是太繁琐,所以Python允许你在list或tuple前面加一个*
号,把list或tuple的元素变成可变参数传进去:
1 | >>> nums = [1, 2, 3] |
*nums
表示把nums
这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。
关键字参数
可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict
1 | def person(name, age, **kw): |
函数person
除了必选参数name
和age
外,还接受关键字参数kw
。在调用该函数时,可以只传入必选参数:
1 | 'Michael', 30) person( |
也可以传入任意个数的关键字参数:
1 | 'Bob', 35, city='Beijing') person( |
*args
是可变参数,args接收的是一个tuple;
**kw
是关键字参数,kw接收的是一个dict。
本章练习
写出函数可计算一个或多个数的乘积,能够处理无参数输入的情况
1 | def mul(firstNum, *numbers): |
递归
汉诺塔
1 | def move(n, a, b, c): |
高级特性
切片
1 | L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack'] |
取一个list或tuple的部分元素,可以使用py的切片操作符
L[0:3]
表示,从索引0
开始取,直到索引3
为止,**但不包括索引3
**。即索引0
,1
,2
,正好是3个元素。
如果第一个索引是0
,还可以省略:L[:3]
类似的,既然Python支持L[-1]
取倒数第一个元素,那么它同样支持倒数切片,如下:
1 | 2:] L[- |
其他应用:
1
L = list(range(100))
在前10个数中,每两个取一个:
1
2>>> L[:10:2]
[0, 2, 4, 6, 8]所有数,每5个取一个:
1
2>>> L[::5]
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]甚至什么都不写,只写
[:]
就可以原样复制一个list:1
2>>> L[:]
[0, 1, 2, 3, ..., 99]tuple也是一种list,唯一区别是tuple不可变。因此,tuple也可以用切片操作,只是操作的结果仍是tuple:
1
2>>> (0, 1, 2, 3, 4, 5)[:3]
(0, 1, 2)字符串
'xxx'
也可以看成是一种list,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串:1
2
3
4>>> 'ABCDEFG'[:3]
'ABC'
>>> 'ABCDEFG'[::2]
'ACEG'
练习:去除字符串开头和结尾的空格
1 | def trim(s): |
迭代
如果给定一个list
或tuple
,我们可以通过for
循环来遍历这个list
或tuple
,这种遍历我们称为迭代(Iteration)。
在Python中,迭代是通过for ... in
来完成的,而很多语言比如C语言,迭代list
是通过下标完成的
Python的for
循环不仅可以用在list
或tuple
上,还可以作用在其他可迭代对象上。
list
这种数据类型虽然有下标,但很多其他数据类型是没有下标的,但是,只要是可迭代对象,无论有无下标,都可以迭代,比如dict
就可以迭代:
1 | d = {'a': 1, 'b': 2, 'c': 3} |
因为
dict
的存储不是按照list
的方式顺序排列,所以,迭代出的结果顺序很可能不一样
默认情况下,dict
迭代的是key。如果要迭代value,可以用for value in d.values()
,如果要同时迭代key和value,可以用for k, v in d.items()
。由于字符串也是可迭代对象,因此,也可以作用于
for
循环最后一个小问题,如果要对
list
实现类似Java那样的下标循环怎么办?Python内置的enumerate
函数可以把一个list
变成索引-元素对,这样就可以在for
循环中同时迭代索引和元素本身:1
2
3
4
5
6for i, value in enumerate(['A', 'B', 'C']):
print(i, value)
...
0 A
1 B
2 C上面的
for
循环里,同时引用了两个变量,在Python里是很常见的,比如下面的代码:1
2
3
4
5
6for x, y in [(1, 1), (2, 4), (3, 9)]:
print(x, y)
...
1 1
2 4
3 9
练习:返回list中的最大值和最小值为tuple类型
1 | def findMinAndMax(L): |
- 列表生成式之后的内容 待续…
- 本文链接:https://wan-nan.github.io/2021/07/06/py%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E6%94%BE%E5%BC%83/
- 版权声明:本博客所有文章除特别声明外,均默认采用 许可协议。