Python 编码
-
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保存到文件。
-
在最新的Python 3版本中,字符串是以Unicode编码的,也就是说,Python的字符串支持多语言,
-
对于单个字符的编码,Python提供了ord()函数获取字符的整数编码表示,chr()函数把编码转换为对应的字符。
List
-
Python内置的一种数据类型是列表:list。list是一种有序的集合,可以随时添加和删除其中的元素。
-
当索引超出了范围时,Python会报一个IndexError错误,如果要取最后一个元素,除了计算索引位置外,还可以用-1做索引,直接获取最后一个元素.
-
insert(index,元素)可以把元素插入到指定的位置,该位置及其后的元素会往后移动一位
tuple
-
另一种有序列表叫元组:tuple。tuple和list非常类似,但是tuple一旦初始化就不能修改,比如同样是列出同学的名字.
-
要定义一个只有1个元素的tuple;如果你这么定义t = (1); 定义的不是tuple,是1这个数!这是因为括号()既可以表示tuple,又可以表示数学公式中的小括号,这就产生了歧义,因此,Python规定,这种情况下,按小括号进行计算,计算结果自然是1。所以,只有1个元素的tuple定义时必须加一个逗号,,来消除歧义t = (1,)。
-
tuple的不变指的是引用不变,比如里面存的是对象,改变对象的某些属性,但这个对象没有变,即tuple的元素未变。
dict
-
Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。
-
为什么dict查找速度这么快?因为dict的实现原理和查字典是一样的。假设字典包含了1万个汉字,我们要查某一个字,一个办法是把字典从第一页往后翻,直到找到我们想要的字为止,这种方法就是在list中查找元素的方法,list越大,查找越慢。第二种方法是先在字典的索引表里(比如部首表)查这个字对应的页码,然后直接翻到该页,找到这个字。无论找哪个字,这种查找速度都非常快,不会随着字典大小的增加而变慢。dict就是第二种实现方式,给定一个名字,比如'Michael',dict在内部就可以直接计算出Michael对应的存放成绩的“页码”,也就是95这个数字存放的内存地址,直接取出来,所以速度非常快。
set
-
集合(set)是一个无序的不重复元素序列。
-
可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。
-
创建格式:parame = {value01,value02,...} 或者 set(value)
函数
函数的参数
-
位置参数,power(x, n)函数有两个参数:x和n,这两个参数都是位置参数,调用函数时,传入的两个值按照位置顺序依次赋给参数x和n。
-
默认参数,设置有默认值的参数
-
可变参数,定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数。如def calc(*numbers):
-
关键字参数,可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。如def person(name, age, **kw):
迭代
- 判断一个对象是可迭代对象。方法是通过collections模块的Iterable类型判断
from collections import Iterable
isinstance('abc', Iterable) # str是否可迭代
- 如果要对list实现类似Java那样的下标循环。Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身
for i, value in enumerate(['A', 'B', 'C']):
print(i, value)
列表生成式
-
列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。
-
如果要生成[1x1, 2x2, 3x3, ..., 10x10]怎么做?方法一是循环:
>>> L = []
>>> for x in range(1, 11):
... L.append(x * x)
...
>>> L
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
- 但是循环太繁琐,而列表生成式则可以用一行语句代替循环生成上面的list:写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来,十分有用,多写几次,很快就可以熟悉这种语法。
>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
- for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:
>>> [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']
生成器
-
如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
-
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
at 0x1022ef630>
-
可以通过next()函数获得generator的下一个返回值,generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
-
当然,不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象:
>>> g = (x * x for x in range(10))
>>> for n in g:
... print(n)
- 如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator,如
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
- 这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
迭代器
-
凡是可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
-
凡是可作用于for循环的对象都是Iterable类型;
-
可以使用isinstance()判断一个对象是否是Iterator对象
-
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
-
把list、dict、str等Iterable变成Iterator可以使用iter()函数
-
为什么list、dict、str等数据类型不是Iterator?这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
-
Python的for循环本质上就是通过不断调用next()函数实现的