一、编码
ASCII编码、Unicode编码、可变长编码”的UTF-8编码之间的由来
由于计算机是美国人发明的,因此,最早只有127个字符被编码到计算机里,这个编码表被称为ASCII编码,但是要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突,所以,中国制定了GB2312编码,用来把中文编进去。你可以想得到的是,全世界有上百种语言,各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。
Unicode应运而生。Unicode把所有语言都统一到一套编码里。如果统一成Unicode编码,乱码问题从此消失了。但是,如果你写的文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间。
于是乎又出现了把Unicode编码转化为“可变长编码”的UTF-8编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。
二、字符串
在最新的Python 3版本中,字符串是以Unicode编码的
- 单个字符的编码
ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符:
>>> ord('中')
20013
>>> chr(25991)
'文'
如果知道字符的整数编码,还可以用十六进制这么写str:
>>> '\u4e2d\u6587'
'中文'
- 由于Python的字符串类型是str,在内存中以Unicode表示,一个字符对应若干个字节。如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes。
x = b'ABC'
以Unicode表示的str通过encode()方法可以编码为指定的bytes,例如:
>>> 'ABC'.encode('ascii')
b'ABC'
反过来从网络或磁盘上读取了字节流,要把bytes变为str,就需要用decode()方法:
- 要计算str包含多少个字符,可以用len()函数:
>>> len('ABC')
3
len()函数计算的是str的字符数,如果换成bytes,len()函数就计算字节数:
例如:>>> len('中文'.encode('utf-8')) // 6 ; >>> len(b'ABC') //3;
由于Python源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8编码。当Python解释器读取源代码时,为了让它按UTF-8编码读取,我们通常在文件开头写上这两行:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
第一行注释是为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释;
第二行注释是为了告诉Python解释器,按照UTF-8编码读取源代码,否则,你在源代码中写的中文输出可能会有乱码。
申明了UTF-8编码并不意味着你的.py文件就是UTF-8编码的,必须并且要确保文本编辑器正在使用UTF-8 without BOM编码:
三、格式化
>>> 'Hello, %s' % 'world'
'Hello, world'
>>> 'Hi, %s, you have $%d.' % ('Michael', 1000000)
'Hi, Michael, you have 00000.'
%运算符就是用来格式化字符串的。在字符串内部,%s表示用字符串替换,%d表示用整数替换,有几个%?占位符,后面就跟几个变量或者值,顺序要对应好。如果只有一个%?,括号可以省略。
常见的占位符有:%d 整数 / %f 浮点数 /%s 字符串 /%x 十六进制整数
- 格式化整数和浮点数还可以指定是否补0和整数与小数的位数:
print('%2d-%02d' % (3, 1)) // 3-01 2d代表两位整数,但由于第一个2d前面无0,所以 3的前面未补0 , 1的前面补0
print('%.2f' % 3.1415926) //3.14 保留了两位小数
有些时候,字符串里面的%是一个普通字符怎么办?这个时候就需要转义,用%%来表示一个%:
- format() //另一种格式化字符串的方法
>>> 'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125)
'Hello, 小明, 成绩提升了 17.1%'
四、数据类型
list
list是一种有序的集合,是一种数据类型。类似JS里的数组
- 注意:当超出索引值的时候Python会报IndexError错误
- 可以用-1做索引,直接获取最后一个元素,如: classmates[-1] //'Tracy',以此类推,可以获取倒数第2个、倒数第3个:
- len()函数可以获得list元素的个数,如:len(classmates)
- classmates.insert(1, 'Jack') 往指定位置插入元素
- classmates.append('Adam')往末尾追加元素
- classmates.pop(1) 删除指定位置的元素
- classmates[1] = 'Sarah';把某个元素替换成别的元素
- list元素也可以是另一个list ;s = ['python', 'java', ['asp', 'php'], 'scheme']
- list里面的元素的数据类型也可以不同
[1] + [2] + [3] == [1,2,3]
tuple
tuple是另一种有序的集合,是一种数据类型。tuple和list非常类似,但是tuple一旦初始化就不能修改
classmates = ('Michael', 'Bob', 'Tracy')
要定义一个只有1个元素的tuple,方式如下:
#正确的
t = (1,) //(1,)
#错误的 定义的不是tuple,是1这个数!此时()为数学公式中的小括号
t = (1)//1
dict(类似Object)
d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
d['Michael'] #95
d['Adam'] = 67
d['Adam'] #67
a[' aaaa'] #报错,但是如果是JS不报错,输出undefined
判断key 在不在dict里面
- in
'Thomas' in d #False
- get()
d.get('Thomas') #如果key不存在,可以返回None
删除key
d.pop('Bob')
编写一个Dict类,这个类的行为和dict一致,但是可以通过属性来访问,
>>> d = Dict(a=1, b=2)
>>> d['a']
1
>>> d.a
1
set
是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key。
s = set([1, 2, 3]) #s {1, 2, 3}
- add()
add(key)方法可以添加元素到set中,可以重复添加,但不会有效果: - remove()
remove(key)方法可以删除元素: - set可以看成数学意义上的无序和无重复元素的集合,因此,两个set可以做数学意义上的交集、并集等操作:
>>> s1 = set([1, 2, 3])
>>> s2 = set([2, 3, 4])
>>> s1 & s2
{2, 3}
>>> s1 | s2
{1, 2, 3, 4}
五、切片 方法
list
取前N个元素,也就是索引为0-(N-1)的元素,L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3;如果第一个索引是0,还可以省略:表示为L[:3],也支持 L[-2:],表示从倒数第二个开始取至最后一个。
L = list(range(100))
L[:10:2] #前10个数,每两个取一个:
L[::5] #所有数,每5个取一个:[0, 2, 4, 6, 8]
L[:] #只写[:]就可以原样复制一个list:[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]
tuple
tuple类似,唯一区别是切片后仍为tuple
>>> (0, 1, 2, 3, 4, 5)[:3]
(0, 1, 2)
字符串
字符串也类似,唯一区别是切片后仍为字符串
>>> 'ABCDEFG'[:3]
'ABC'
用切片重写str的strim()方法
def trim(s):
if len(s) == 0:
return s
elif s[0] == ' ':
return (trim(s[1:]))
elif s[-1] == ' ':
return (trim(s[:-1]))
return s
print(trim(" 23a "))
六、if和循环
条件判断
age = 3
if age >= 18:
print('your age is', age)
print('adult')
else:
print('your age is', age)
print('teenager')
也可以用elif做更细致的判断
例子
s = input('birth: ')
birth = int(s) # input()返回的数据类型是str
if birth < 2000:
print('00前')
else:
print('00后')
循环
for ... in ...
names = ['Michael', 'Bob', 'Tracy']
for name in names:
print(name)
while(和JS一样)
break和continue的区别:
- break的作用是提前结束循环。
- continue的作用是提前结束本轮循环,并直接开始下一轮循环。
七、其他特性
迭代
如何判断一个对象是可迭代对象
from collections import Iterable
print(isinstance('abc', Iterable)) # str是否可迭代
如果你的Python在3.8+,则会有警告提示:
DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
from collections import Iterable
Python内置的enumerate函数可以把一个list变成索引-元素对
for i, value in enumerate(['A', 'B', 'C']):
... print(i, value)
...
0 A
1 B
2 C
#for循环里,同时引用了两个变量
for x, y in [(1, 1), (2, 4), (3, 9)]:
... print(x, y)
...
1 1
2 4
3 9
问题:请用迭代的方法查找一个list里面的最小值和最大值,并返回一个tuple
def findMinAndMax(L):
min = L[0]
max = L[0]
for i in L[1:]:
if i>max:
max = i
elif i< min:
min = i
return(min,max)
print(findMinAndMax([6,2,3,4]))
列表生成式
list(range(1, 11)) 得到 list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
[x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]
[m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
#循环dict的items()来生成list
>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> [k + '=' + v for k, v in d.items()]
['y=B', 'x=A', 'z=C']
问题:将一个单项类型不都为字符串的list里面所有字符串转化为小写字母,并生成新的list
L = ['Hello', 'World', 18, 'Apple', None]
print([s.lower() for s in L if isinstance(s, str)])
生成器 generator
创建一个generator
1.把一个列表生成式的[]改成(),就创建了一个generator:
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>
但此时我们怎么打印出generator的每一个元素呢?可以通过next()函数获得generator的下一个返回值。
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
...
#或者
>>> g = (x * x for x in range(10))
>>> for n in g: #因为generator也是可迭代对象:所以也可以使用for循环
... print(n)
...
斐波拉契数列
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
return 'done'
要把fib函数变成generator,只需要把print(b)改为yield 就可以了:
注意:
a.对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。
b.如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator
问题:把每一行看做一个list,试写一个generator,不断输出下一行的list
def yhTriangle(n):
l, index = [1], 0
while index < n:
yield l
l = [1] + [l[i] + l[i + 1] for i in range(len(l) - 1)] + [1]
index += 1
l = yhTriangle(3)
for item in l:
print(item)
迭代器
可以直接作用于for循环的对象统称为可迭代对象:Iterable。
如:list、tuple、dict、set、str、generator,包括生成器和带yield的generator function。
可以使用isinstance()判断一个对象是否是Iterable对象:
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。
可以使用isinstance()判断一个对象是否是Iterator对象:它们表示一个惰性计算的序列;