#!/usr/bin/env python3 # -*- encoding: utf-8 -*- print('Hello world') print('中国心')
python程序本质是脚本语言,与shell相同,都是顺序逐条语句执行,语句执行完成后退出。没有main函数。
00.python程序格式
#开头的语句是注释,其他每一行都是一个语句。
语句以冒号(:)结尾时,缩进的语句视为代码块(没有C语言中{}区分代码块)。
约定俗称, 4个空格缩进,Tab或空格均可以,但要保持一致。
python大小写敏感。
0.unicode&utf-8
在计算机内存中,统一使用unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为utf-8编码。
用记事本编辑的时候,从文件读取的utf-8字符被转换为unicode字符到内存里,编码完成保存时再把unicode转换为utf-8保存到文件。
浏览网页时,服务器会把动态生成的unicode内容转换为utf-8再传输给浏览器,所以会看到许多网页的源码上会有类似<meta charset="UTF-8" />的信息,表示该网页正是用的utf-8编码。
1. 除法
Python中有两种除法,一种除法是/,/除法计算结果永远是浮点数。
地板除//,计算结果永远是整数。
余数运算%。
无论整数做//
除法还是取余数,结果永远是整数,所以,整数运算结果永远是精确的。
2. 布尔值类型
布尔值类型只有Truce、False两种值(注意Python大小写敏感)。
布尔值可以用and,or,和not运算。
3. 空值
空值是Python里一个特殊的值,用None表示。None不能理解为0,因为0是有意义的,而None是一个特殊的空值。
4. 常量
在Python中,通常用全部大写的变量名表示常量。
5. bytes类型
Python对bytes
类型的数据用带b
前缀的单引号或双引号表示:
x=b'ABC'
要注意区分'ABC'
和b'ABC'
,前者是str
,后者虽然内容显示得和前者一样,但bytes
的每个字符都只占用一个字节。
纯英文的str
可以用ASCII
编码为bytes
,内容是一样的,含有中文的str
可以用UTF-8
编码为bytes
。含有中文的str
无法用ASCII
编码,因为中文编码的范围超过了ASCII
编码的范围,Python会报错。
在bytes
中,无法显示为ASCII字符的字节,用x##
显示。
b''(b前缀):每个字节占用一个字节。print(b'A A') ---b'A A'
u''(u前缀)或无前缀:字符串默认以Unicode编码存储,可以存储中文。Unicode中每个字符占用两个字节。print(u'A A') ---A A
r''(r前缀):主要解决转义字符、特殊字符问题,其中所有字符均被视为普通字符。print(r'A A')--A A
6. str和bytes转换
由于Python的字符串类型是str,在内存中以unicode表示,一个字符对应若干个字节。如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes。以unicode表示的str通过encode()方法可以编码为指定的bytes;反过来,从网络或磁盘上读取了字节流,读取到的数据是bytes,用decode()将bytes变为str。
在操作字符串时,我们经常遇到str
和bytes
的互相转换。为了避免乱码问题,应当始终坚持使用UTF-8编码对str
和bytes
进行转换。
>>> '中文'.encode('utf-8') b'xe4xb8xadxe6x96x87' >>> b'xe4xb8xadxe6x96x87'.decode('utf-8') '中文' >>> '33345'.encode('utf-8') b'33345' >>> '中8'.encode('utf-8') b'xe4xb8xad8' >>> b'xe4xb8xad8'.decode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128) >>> b'xe4xb8xad8'.decode('utf-8') '中8'
7. 输入输出
输入用input(),输出用print()。
input()可以输入提示字符串,input()返回的数据类型是str,str不能直接和整数比较。
>>> name=input('please enter your name:') please enter your name:wang >>> print('hello,', name) hello, wang >>> job="IT" >>> print('hello', name, job) hello wang IT
8. 格式化
%运算符用来格式化字符串。
%用来分割格式化子串和格式化参数,多个格式化参数时要用括号包围。
在字符串内部,%s表示用字符串替换,%d表示用整数替换,有几个%?占位符,后面就跟几个变量或值,顺序要对应好。如果只有一个%?,括号可以忽略。
>>> 'Hello, %s' % 'world' 'Hello, world' >>> 'Hi, %s, you have $%d' % ('Michael', 100000) 'Hi, Michael, you have $100000' >>> print('Hi, %s, you have $%d', 'Michael', 10000) Hi, %s, you have $%d Michael 10000 >>> print('Hi, %s, you have $%d' % 'Michael', 10000) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: not enough arguments for format string >>> print('Hi, %s, you have $%d' % ('Michael', 10000)) Hi, Michael, you have $10000
注:必须用%分割格式化子串和参数,不能像C语言一样用逗号(,),否则后面的参数被作为字符串处理(字符串拼接)。
9.数组和元组
list是一种有序的集合,就是数组([])。索引从0开始,可用-1获取最后一个元素。
可用len()获取list元素个数。
list支持的函数append(element),insert(index,element),pop(),pop(index)。
list里元素类型可以不同,可以内嵌另一个list,支持二维数组、三维数组……
tuple是元组,一旦初始化就不能修改,用()标识。
tuple没有append()和insert()方法,因为它不支持修改元素。
tuple的陷阱:当定义一个tuple时,tuple的元素就必须被确定下来。
定义一个空的tuple,可以写成(),如t=()。
定义只有一个元素的tuple,需写成(1,),如t=(3,),而不能是t=(3)。这是因为括号()既可以表示tuple,又可以表示数学公式中的小括号,这就产生了歧义,因此,Python规定,这种情况下,按小括号进行计算,计算结果自然是3。所以,只有1个元素的tuple定义时必须加一个逗号,,来消除歧义。
>>> t=(3,) >>> t (3,) >>> t=(3) >>> t 3
看一个可变tuple的例子:
>>> t = ('a', 'b', ['A', 'B']) >>> t[2][0] = 'X' >>> t[2][1] = 'Y' >>> t ('a', 'b', ['X', 'Y'])
t是一个元组,内嵌一个list,内嵌的list地址不变,变得是list指向的存储的内容。
tuple的元素确实变了,但其实变的不是tuple的元素,而是list的元素。tuple一开始指向的list并没有改成别的list,所以,tuple所谓的“不变”是说,tuple的每个元素,指向永远不变。即指向'a',就不能改成指向'b',指向一个list,就不能改成指向其他对象,但指向的这个list本身是可变的!
理解了“指向不变”后,要创建一个内容也不变的tuple怎么做?那就必须保证tuple的每一个元素本身也不能变。
10.条件判断
if <条件判断1>: <执行1> elif <条件判断2>: <执行2> elif <条件判断3>: <执行3> else: <执行4> if判断条件还可以简写,比如写: if x: print('True')
只要x是非零数值、非空字符串、非空list等,就判断为True,否则为False。
11.循环
for x in ...循环就是把每个元素代入变量x,然后执行缩进块的语句。
sum = 0 for x in range(101): sum = sum + x print(sum)
如果要计算1-100的整数之和,从1写到100有点困难,幸好Python提供一个range()函数,可以生成一个整数序列,再通过list()函数可以转换为list。
python也支持while循环和break/continue:
n = 1 while n <= 100: if n > 10: # 当n = 11时,条件满足,执行break语句 break # break语句会结束当前循环 print(n) n = n + 1 print('END')
n = 0 while n < 10: n = n + 1 if n % 2 == 0: # 如果n是偶数,执行continue语句 continue # continue语句会直接继续下一轮循环,后续的print()语句不会执行 print(n)
break语句可以在循环过程中直接退出循环,而continue语句可以提前结束本轮循环,并直接开始下一轮循环。这两个语句通常都必须配合if语句使用。
12. dict
python内置了字典:dict的支持,dictionary,用{}标识。在其他语言中也称为map,使用key-value存储,具有极快的查找速度。一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉。dict中key必须是不可变对象。字符串、整数等都是不可变的,list是可变的,因此list不能用作key。
>>> d={'wang':100,'chen':120,'zhang':130} >>> d['wang'] 100 >>> d {'wang': 100, 'chen': 120, 'zhang': 130} >>> d['zhang']=140 >>> d {'wang': 100, 'chen': 120, 'zhang': 140} >>> d['xue'] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'xue' >>> d={'wang':100,'chen':120,'zhang':130} >>> d {'chen': 120, 'zhang': 130, 'wang': 100} >>> d['xu']=130 >>> d {'chen': 120, 'xu': 130, 'zhang': 130, 'wang': 100}
判断key是否在dict中有两种方法:1)key in dict;2)get(),如果key不存在,返回None,或者自己指定的value:
>>> 'wang' in d True >>> xue in d Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'xue' is not defined >>> wang in d Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'wang' is not defined >>> d.get('wang') 100 >>> d.get('xue') >>>
注意:返回None的时候Python的交互环境不显示结果。
删除一个key用pop(key):
100 >>> d {'chen': 120, 'zhang': 140}
请务必注意,dict内部存放的顺序和key放入的顺序是没有关系的。
13.set
set也是一个key的集合,但不存储value。由于key不能重复,所以在set中,没有重复的key。
要创建一个set,需要提供一个list作为输入集合:
>>> s = set([1, 2, 3]) >>> s {1, 2, 3}
注意,传入的参数[1, 2, 3]是一个list,而显示的{1, 2, 3}只是告诉你这个set内部有1,2,3这3个元素,显示的顺序也不表示set是有序的。
通过add(key)方法可以添加元素到set中,可以重复添加,但不会有效果。通过remove(key)方法可以删除元素。
>>> s.add(4) >>> s {1, 2, 3, 4} >>> s.add(4) >>> s {1, 2, 3, 4}
set可以看成数学意义上的无序和无重复元素的集合,因此,两个set可以做数学意义上的交集、并集等操作:
>>> s1 = set([1, 2, 3]) >>> s2 = set([2, 3, 4]) >>> s1 & s2 {2, 3} >>> s1 | s2 {1, 2, 3, 4}
set和dict的唯一区别仅在于没有存储对应的value,但是,set的原理和dict一样,所以,同样不可以放入可变对象,因为无法判断两个可变对象是否相等,也就无法保证set内部“不会有重复元素”。
14. 切片
切片是提取一个list或tuple的部分元素。
1)切片用冒号界定区间,L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3。即索引0,1,2,正好是3个元素。
2)如果第一个索引是0,还可以省略。
3)[:]就可以原样复制一个list。
4)切片可以进一步过滤条件,若[:10:2]表示前10个数每两个取一个,[::5]所有数每5个取一个。
5)Python支持L[-1]取倒数第一个元素,python同样支持倒数切片。
>>> L=list(range(100)) >>> L [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99] >>> L[::5] [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95] >>> L[-10:] [90, 91, 92, 93, 94, 95, 96, 97, 98, 99] >>> L[::10] [0, 10, 20, 30, 40, 50, 60, 70, 80, 90] >>> L[30:40] [30, 31, 32, 33, 34, 35, 36, 37, 38, 39]
tuple和字符串同样适合切片提取元素。
15.迭代iterate
python中迭代通过for…in来实现。
list、tupple、dict、set、str都可以迭代。
dict迭代的是key。如果要迭代value,可以用for value in d.values(),如果要同时迭代key和value,可以用for k, v in d.items()。
>>> d={'a':1, 'b':2, 'c':3, 'd':4} >>> for key in d: ... print(key) ... a b d c >>> for k,v in d.items(): ... print('%s is %d' %(k,v)) ... a is 1 b is 2 d is 4 c is 3
如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断:
>>> from collections import Iterable >>> isinstance('abc', Iterable) # str是否可迭代 True >>> isinstance([1,2,3], Iterable) # list是否可迭代 True >>> isinstance(123, Iterable) # 整数是否可迭代 False
如果要对list实现类似C那样的下标循环怎么办?Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:
>>> for i,t in enumerate([(1,1),(2,4),(3,9)]): ... print(i, t) ... 0 (1, 1) 1 (2, 4) 2 (3, 9)
16.list comprehensions列表生成式
写列表生成式时,就是把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来。
>>> LL=[x*x for x in range(10)] >>> LL [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:
>>> LL=[x*x for x in range(10) if x%2==0] >>> LL [0, 4, 16, 36, 64]
还可以使用两层循环,可以生成全排列:
>>> [m+n for m in 'abc' for n in 'XYZ'] ['aX', 'aY', 'aZ', 'bX', 'bY', 'bZ', 'cX', 'cY', 'cZ']
17.生成器
通过列表生成式,可以直接创建一个列表。但是,受到内存限制,列表的容量是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。一边循环一边计算的机制,称为生成器generator。generator有两种实现方式:列表生成式或函数。
基于list comprehensions的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 <generator object <genexpr> at 0x1022ef630>
创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator。
通过next(g)可以一个一个地打印generator的值。
generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
>>> g=(x*x for x in range(2)) >>> next(g) 0 >>> next(g) 1 >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
对于generator,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误。
基于函数的generator
如果一个函数定义中包含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语句处继续执行。
18.迭代器
可以直接作用于for循环的数据类型有以下几种:
一类是集合数据类型,如list、tuple、dict、set、str等;
一类是generator,包括生成器和带yield的generator function。
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。可以使用isinstance()判断一个对象是否是Iterable对象:
>>> from collections 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
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
可以使用isinstance()判断一个对象是否是Iterator对象:
>>> from collections 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()函数:
>>> isinstance(iter([]), Iterator) True >>> LLL=list(range(5)) >>> IT=iter(LLL) >>> IT <list_iterator object at 0x7f454b9abb38> >>> next(IT) 0 >>> for x in IT: ... print(x) ... 1 2 3 4
为什么list、dict、str等数据类型不是Iterator?
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
参考:
2. https://naveenr.net/unicode-character-set-and-utf-8-utf-16-utf-32-encoding/
3. Python成长之路