python基础归结

荒凉一梦 提交于 2019-12-26 01:18:12
#!/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##显示。

6. str和bytes转换

由于Python的字符串类型是str,在内存中以unicode表示,一个字符对应若干个字节。如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes。以unicode表示的str通过encode()方法可以编码为指定的bytes;反过来,从网络或磁盘上读取了字节流,读取到的数据是bytes,用decode()将bytes变为str。

在操作字符串时,我们经常遇到strbytes的互相转换。为了避免乱码问题,应当始终坚持使用UTF-8编码对strbytes进行转换。

>>> '中文'.encode('utf-8')
b'\xe4\xb8\xad\xe6\x96\x87'
>>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
'中文'
>>> '33345'.encode('utf-8')
b'33345'
>>> '中8'.encode('utf-8')
b'\xe4\xb8\xad8'
>>> b'\xe4\xb8\xad8'.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'\xe4\xb8\xad8'.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)insertindexelement),pop(),popindex)。

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,后面的值会把前面的值冲掉。dictkey必须是不可变对象。字符串、整数等都是不可变的,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中有两种方法:1key in dict2get(),如果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的交互环境不显示结果。

删除一个keypop(key):

100
>>> d
{'chen': 120, 'zhang': 140}

请务必注意,dict内部存放的顺序和key放入的顺序是没有关系的。

13set

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内部有1233个元素,显示的顺序也不表示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}

setdict的唯一区别仅在于没有存储对应的value,但是,set的原理和dict一样,所以,同样不可以放入可变对象,因为无法判断两个可变对象是否相等,也就无法保证set内部“不会有重复元素”。

14. 切片

切片是提取一个listtuple的部分元素。

1)切片用冒号界定区间,L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3。即索引012,正好是3个元素。

2)如果第一个索引是0,还可以省略。

3[:]就可以原样复制一个list

4)切片可以进一步过滤条件,若[:10:2]表示前10个数每两个取一个,[::5]所有数每5个取一个。

5Python支持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来实现。

listtuppledictsetstr都可以迭代。

dict迭代的是key。如果要迭代value,可以用for value in d.values(),如果要同时迭代keyvalue,可以用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)

16list 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万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。一边循环一边计算的机制,称为生成器generatorgenerator有两种实现方式:列表生成式或函数。

基于list comprehensionsgenerator

只要把一个列表生成式的[]改成(),就创建了一个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>

创建Lg的区别仅在于最外层的[]()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循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是generator,包括生成器和带yieldgenerator 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对象,但listdictstr虽然是Iterable,却不是Iterator

listdictstrIterable变成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

为什么listdictstr等数据类型不是Iterator

这是因为PythonIterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

  

参考:

1. 廖雪峰python教程之字符串和编码

2. https://naveenr.net/unicode-character-set-and-utf-8-utf-16-utf-32-encoding/

3. Python成长之路

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!