python入门指南
python是一门简单易学且功能强大的编程语言。它拥有高效的高级数据结构,并且能够简单而又高效的方式进行面向对象编程。
python是一门解释性语言,因为无需编译和链接,在开发中节省时间。
使用python解释器
调用python解释器
python解释器通常被安装在目标机器的/user/local/bin/python3.4目录下,将/user/local/bin目录包含进Unix shell的搜索路径里,以确保可以通过输入:python3.4 命令来启动它。
在windows机器上,python通常安装在c:\python3.4位置,你可以在运行安装向导时修改此值。想要把此目录添加到你的PATH环境变量中,你可以在DOS窗口中输入以下命令:
set path=%path%;c:\ptrhon33
由于python语句通常会包含空格或其他特殊shell字符,一般建议将命令用单引号包裹起来。
参数传递
解释器会读取命令行参数,转化为字符串列表存入sys模块中的argv变量中。执行命令import sys你可以导入这个模块并访问这个列表。
交互模式
在交互模式下,根据主提示符来执行,主提示符通常标识为三个大于号(>>>),继续的部分被称为从属提示符,有三个点标识(…)。在第一行之前,解释器打印欢迎信息,版本和授权提示:
解释器及其环境
错误处理
在主提示符或附属提示符输入中断符(通常时ctrl+C或者DEL)就会取消当前输入,回到主命令行。执行命令时输入一个中断符会抛出一个keyboardInterrupt异常,它可以被try语句截获。
执行pthon脚本
python脚本可以像shell脚本那样执行,只要在脚本文件开头写一行命令,指定文件和模式。
#!/user/bin/evn python3.3
(要确认python解释器在用户的PATH中)
脚本可以通过chmod命令指定执行模式和权限
$ chmod +x myscript.py
源程序编码
默认情况下,python源文件是UTF-8编码。
你也可以为源文件指定不同的字符编码。为此,在#!行(首行)后插入至少一行特殊的注释行来定义源文件的编码
# -*- coding:encoding -*-
通过此声明,源文件中所有的东西都会被当作用encoding指代的UTF-8编码对待。
交互执行文件
你可以在一个文件中包含你想要执行的命令,设定一个名为PYTHONSTARTUP的环境变量来指定这个文件。
如果你想要在当前的目录中执行附加的启动文件,可以在全局启动文件中加入类似以下的代码:
if os.path.isfile('.pythonrc.py'): execfile('.pythonrc.py')。
如果你想要在某个脚本中使用启动文件,必须要在脚本中写入这样的语句:
import os
filename = os.environ.get('PYTHONSTARTUP')
if filename and os.path.isfile(filename):
exec(open(filename).read())
本地化模块
python提供了两个钩子(方法)来本地化:sitecustomize和usercustomize。为了见识他们,你首先需要找到你的site-packages的目录,启动python执行下面的代码:
import site
site.getusersitepackages()
'C:\\Users\\86159\\AppData\\Roaming\\Python\\Python36\\site-packages'
python简介
将python当做计算器
数字
解释器的表示就像一个简单的计算器:可以向其录入一些表达式,它会给出返回值。表达式语法很直白:运算符+,-,*,/,与其他语言一样,:括号用于分组。
注意:有时你可能会得到不同的结果:浮点数在不同机器上的运算结果可能是不同的。
对整数做除法运算并想去除小数部分取得整数结果时,可以使用另外一个运算符, //:
等号(’=’)用于给变量赋值。一个值可以同时赋值给几个变量。变量在使用前必须"定义"(赋值),否则会出错。
浮点数有完整的支持:与整型混合计算时会自动转为浮点数。
字符串
python也提供了可以通过几种不同的方式传递的字符串。他们可以用单引号或双引号标识。
字符串文本有几种方法分行。可以使用反斜杠为行结尾的连续字符串,它表示下一行在逻辑上是本行的后续内容。
字符串文本有几种分行的方法。可以使用反斜杠为行结尾的连续字符串,它表示下一行在逻辑上是本行的后续内容。
字符串可以标识在一对儿三引号中。不需要行属转义,它们已经包含在字符串中。
字符串可以由+操作符连接(粘到一起),可以由*重复。
字符串可以被截取(检索)可以用切片标注法截取字符串:由两个索引分割的复本。
索引切片可以有默认值,切片时,忽略第一个索引的话,默认为0,忽略第二个索引,默认为字符串的长度。
python字符串不可变。向字符串文本的某一个索引赋值会引发错误:
关于Unicode
如果想在字符串中包含特殊字符,你可以使用python的Unicode的编码方式。
>>> 'Hello\u0020World!'
'Hello World!'
转码序列\u0020表示在指定位置插入编码为0x0020的Unicode字符(空格)
字符串对象提供了一个encode()方法用以将字符串转换成特定编码的字节序列,它接收一个小写的编码名称作为参数。
>>> "Apfel".encode('utf-8')
b'Apfel'
列表
列表可以用作中括号之间的一列逗号分隔的值。列表的元素不必是同一类型。
就像字符串索引,列表的元素不必是同一类型。
像字符串索引,列表从0开始检索,列表可以被切片和连接:
所有的切片操作都会返回新的列表,包含求得的元素,这意味着以下的切片操作返回列表a的一个浅拷贝的副本。
列表允许修改元素,可变,也可以对切片赋值。
编程的第一步
写一个生成斐波那契数列的程序
>>> a,b=0,1
>>> while b<10:
... print(b)
... a,b=b,a+b
...
1
1
2
3
5
8
用一个都好结尾就可以禁止输出换行:
>>> a,b=0,1
>>> while b<1000:
... print(b,end=',')
... a,b=b,a+b
...
1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,>>>
深入python流程控制
if语句
if ...elif...elif...序列用于替代其他语言中的switch或case语句
x = int(input("请输入数字:"))
if x < 0:
print('zero')
elif x == 0:
print('one')
elif x == 1:
print('two')
else:
print('three')
for语句
在迭代过程中修改迭代序列不安全(只有在使用链表这样的可变序列时才会有这样的情况)。如果你想要修改迭代的序列,你可以迭代他的复本。使用切割标识就可以很方便的做到这一点。
>>> a = ['wer','ertb','tytyjjj']
>>> for x in a[:]:
... print(x)
... if len(x)>6:
... a.insert(0,x)
...
wer
ertb
tytyjjj
range函数
内置函数range()会很方便,生成一个等差级数链表
需要迭代链表索引,结合使用range()和len()或者enumerate()
在不同方面range()函数返回的对象表现为一个列表,但事实上它并不是。当你迭代它时,它是一个能够像期望的序列返回连续项的对象;但为了节省空间,它并不是真正的构造列表。
list(range(5))
[0,1,2,3,4]
break和continue语句,以及循环中的else子句
break语句,用于跳出最近的一级for或while循环
循环可以有一个else字句,它在循环迭代完整个列表(对于for)或执行条件为false(对于while)时执行,但循环为break中止的情况下不会执行,
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n,'=',x,'*',n//x)
break
else:
print(n)
4 = 2 * 2
6 = 2 * 3
8 = 2 * 4
9 = 3 * 3
pass语句
pass语句什么也不做,它用于那些语法上必须要有什么语句,但是程序什么也不做的场合。
通常用于创建最小结构的类
pass可以在创建新代码时用来做函数或控制体的占位符。可以让你在更抽象的级别上思考。
定义函数
可以创建一个用来生成指定边界的斐波那契数列的函数。
def fib(n):
a, b = 0, 1
while a < n:
# print(a, end=',')
a, b = b, a + b
print(a, end=' ')
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584
函数调用会为函数局部变量生成一个新的符号表。确切的说,所有函数中的变量赋值都是将值存储在局部符号表。变量引用首先在局部符号表中查找,然后是包含函数的局部符号表,然后是全局符号表,最后是内置名字表。因此,全局变量不能在函数中直接赋值(除非用global语句命名),尽管他们可以被引用。
定义一个返回斐波那契数列列表的函数,而不是打印他,是很简单的:
def fib(n):
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a + b
return result
f100 = fib(2000)
print(f100)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597]
深入python函数定义
默认参数值
最常用的形式是为一个或多个参数指定默认值。
默认值只被赋值一次,这使得当默认值是可变对象时会有所不同,比如列表,字典或者大多数类的实例,例如:下面的函数在后续第哦啊用过程中会累计(前面)传给它的参数:
def f(a,L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
[1]
[1, 2]
[1, 2, 3]
如果你不想让默认值在后续调用中累积,你可以像下面一样定义函数:
def f(a,L=None):
if L is None:
L = []
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
[1]
[2]
[3]
关键字参数
函数可以通过关键字参数的形式来调用,形如keyword = value。
可变参数列表
一个最不常用的选择是可以让函数调用可变个数的参数,这些参数被包装进一个元组(元组和序列),在这些可变个数的参数之前,可以有零到多个普通的参数。
参数列表的分拆
当你要传递的参数已经是一个列表,但要调用的函数却接受分开一个个的参数值,这时候你要把已有的列表拆开来,例如,内建函数range()需要独立的start,stop参数,你可以调用函数时,加上一个*操作符来自动把参数列表拆开。
>>> list(range(3,6))
[3, 4, 5]
>>> args = [3,6]
>>> list(range(*args))
[3, 4, 5]
以同样的方式,可以使用**操作符分拆关键字参数为字典:
def parrot(voltage,state='a stiff',action='voom'):
print(voltage,state,action)
d = {"voltage":"four million","state":"bleedin","action":"voom"}
parrot(**d)
four million bleedin voom
Lambda形式
通过lambda关键字,可以创建短小的匿名函数。
文档字符串
插曲:编码风格
对于python,PEP8引入了大多数项目遵循的风格指导。
使用四格缩进,而非TAB,折行以确保不会超过79个字符。
统一函数和类命名,使用文档字符串,注释独占一行,使用空行分隔函数和类,以及函数中的大块代码
数据结构
关于列表更多的内容
python的列表数据类型包含更多的方法。这里是所有的列表对象方法。
list.append(X)
#把一个元素添加到链表的结尾,相当于a[len(a):] = [x]
list.extend(L)
#将一个给定列表中的所有元素都添加到另一个列表中,相当于a[len(a):] = L
list.insert(i,x)
#在指定位置插入一个元素。第一个参数是准备插入到其前面的那个元素的索引,例如a.insert(0,x)会插入到整个链表之前,而a.insert(len(a),x)相当于a.append(x)
list.remove(x)
#删除链表中值为x的第一个元素,
list.pop([i])
#从链表的指定位置删除元素,并将其返回。如果没有指定索引,a.pop()返回最后一个元素。元素随即从链表中被删除。
list.index(x)
#返回链表中第一个值为x的元素的索引,如果没有匹配的元素就会返回一个错误。
list.count(x)
#返回x在链表中出现的次数
list.sort()
#对链表中的元素就地进行排序
list.reverse()
#就地倒排链表中的元素
把链表当作堆栈使用
链表方法使得链表可以很方便的做为一个堆栈来使用,堆栈作为特定的数据结构,最先进入的元素,最后一个被释放(后进先出)。用append()方法可以把一个元素添加到堆栈顶,用不指定索引的pop()方法可以把一个元素从堆栈顶释放出来。
>>> stack = [3,4,5]
>>> stack.append(6)
>>> stack
[3, 4, 5, 6]
>>> stack.pop()
6
把链表当作队列使用
你也可以把链表当做队列使用,队列作为特定的数据结构,最先进入的元素最先释放(先进先出)。不过,列表这样使用效率不高,相对来说从列表末尾添加和弹出很快,在头部插入和弹出很慢(因为,为了一个元素,要移动整个列表中的所有元素)。
要实现队列,使用collections.deque,它为在首尾两端快速插入和删除而设计
>>> from collections import deque
>>> queue = deque(["eric","join","mars"])
>>> queue.append("terry")
>>> queue
deque(['eric', 'join', 'mars', 'terry'])
>>> queue.popleft()
'eric'
>>> queue
deque(['join', 'mars', 'terry'])
列表推导式
列表推导式为从序列中创建列表提供了一个简单的方法,普通的应用程式通过将一些操作应用于序列的每个成员并通过返回的元素创建列表,或者通过满足特定条件的元素创建子序列。
>>> squares = []
>>> for x in range(10):
... squares.append(x*2)
...
>>> squares
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>>
>>> squares = [x*2 for x in range(10)]
>>> squares
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
列表推导式可使用复杂的表达式和嵌套函数:
>>> from math import pi
>>> [str(round(pi,i)) for i in range(1,6)]
['3.1', '3.14', '3.142', '3.1416', '3.14159']
嵌套的列表推导式
列表推导式可以嵌套。
考虑以下的3x4矩阵,一个列表中包含三个长度为4的列表。
>>> matrix = [
... [1,2,3,4],
... [5,6,7,8],
... [9,10,11,12],
... ]
>>> [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
###################################################################
>>> transposed = []
>>> for i in range(4):
... transposed.append([row[i] for row in matrix])
...
>>> transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
################################################################
>>> transposed = []
>>> for i in range(4):
... transposed_row = []
... for row in matrix:
... transposed_row.append(row[i])
... transposed.append(transposed_row)
...
>>> transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
###############################################################
>>> list(zip(*matrix))
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
del语句
从列表中按给定的索引而不是值来删除一个子项:del语句,语句del还可以从列表中删除切片或清空整个列表。
del也可以删除变量
>>> a = [1,2,3,4,5,6]
>>> del a[0]
>>> a
[2, 3, 4, 5, 6]
>>> del a[2:3]
>>> a
[2, 3, 5, 6]
>>> del a[:]
>>> a
元组和序列
一个元组由数个逗号分隔的值组成,例如:
集合
set集合,集合是一个无序不重复元素的集。基本功能包括关系测试和消除重复元素,集合对象还支持union(联合),intersection(交),difference(差),和sysmmetric difference(对称差集)等数学运算。
大括号或set()函数可以用来创建集合。注意,想要创建空集合,必须使用set()而不是{}。后者用于创建空字典。
字典
字典以关键字为索引,关键字可以是任意不可变类型,通常用字符串或数值。如果元组中只包含字符串和数字,它可以做为关键字,如果它直接或间接地包含了可变对象,就不能当做关键字。不能用链表做关键字,因为链表可以用索引,切割或者append()和extend()等方法改变。
>>> tel = {'jack':4098,'sape':4239}
>>> tel['guido']=4127
>>> tel
{'jack': 4098, 'sape': 4239, 'guido': 4127}
>>> tel['jack']
4098
>>> del tel['jack']
>>> tel
{'sape': 4239, 'guido': 4127}
>>> list(tel.keys())
['sape', 'guido']
>>> sorted(tel.keys())
['guido', 'sape']
>>> 'sape' in tel
True
dict()构造函数可以直接从key-value对中创建字典:
>>> dict([('sape',4120),('app',678),('oppo',345)])
{'sape': 4120, 'app': 678, 'oppo': 345}
#字典推导式可以从任意地键值表达式中创建字典:
>>> {x: x*2 for x in (2,4,6)}
{2: 4, 4: 8, 6: 12}
#如果关键字都是简单的字符串,有时通过关键字参数指定key-value对更为方便
>>> dict(sape=234,guide=456,jack=789)
{'sape': 234, 'guide': 456, 'jack': 789}
循环技巧
在字典中循环时,关键字和对应的值可以使用items()方法同时解读出来。
>>> knights = {'glad':'pure','robbit':'red'}
>>> for k,v in knights.items():
... print(k,v)
...
glad pure
robbit red
在序列中循环时,索引位置和对应值可以使用enumerate()函数同时得到。
>>> for i ,v in enumerate(['tic','tac','toe']):
... print(i,v)
...
0 tic
1 tac
2 toe
同时循环两个或更多的序列,可以使用zip()整体打包
questions = ['name','quest','favlor']
answers = ['lasort','hloy','blue']
for q,a in zip(questions,answers):
print('what is your {0}? It is {1}'.format(q,a))
what is your name? It is lasort
what is your quest? It is hloy
what is your favlor? It is blue
需要逆向循环序列的话,先正向定位序列,然后调用reversed()函数。
要按排序后的顺序循环序列的话,使用sorted()函数,它不改动原序列,而是生成一个新的已排序的序列。
深入条件控制
比较序列和其他类型
模块
1.创建一个fibo.py文件。
2.创建内容
def fib(n):
a,b = 0,1
while b<n:
print(b,end=' ')
a,b = b.a+b
3.进入python解释器并使用以下命令导入这个模块:
>>> import fibo
>>> fibo.fib(1000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.__name__
'fibo'
#如果你打算频繁使用一个函数,你可以将它赋予一个本地变量:
>>> fib = fibo.fib
>>> fib(1000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
深入模块
模块可以导入其他的模块
作为脚本来执行模块
当你使用以下方式运行python模块时,模块中的代码便会被执行:
python fibo.py <arguments>
模块中的代码会被执行,就像导入它一样,不过此时__name__
被设置为“__main__”
,这相当于,入宫你在模块后加入如下代码:
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
就可以让此文件像作为模块导入时一样作为脚本执行,此代码只有在模块作为"main"文件执行时才被调用:
$ python fib0.py 50
1 1 2 3 5 8 13 21 34
模块的搜索路径
导入一个spam的模块时,解释器首先在当前目录中搜索名为spam.py的文件,若没找到,接着回到sys.path变量中给出的目录列表中查找。sys.path便量的初始值来自如下:
1.输入脚本的目录(当前目录)
2.环境变量pythonpath表示的目录列表中搜索
3.python默认的安装路径中搜索
编译的python文件
标准模块
变量sys.path是解释器模块搜索路径的字符串列表,它由环境变量pythonpath初始化,如果没有设定pythonpath,就由内置的默认值初始化,你可以用标准的字符串操作修改它。
dir函数
内置函数dir()用于按模块名搜索模块定义,它返回一个字符串类型的存储列表:
包
包通常是使用"圆点模块名"的结构化模块命名空间。
输入输出
格式化输出
两种输出方式:表达式语句和print()函数。
str.zfill()它用于向数值的字符串表达左侧填充0,该函数可以正确理解正负号。
str.format()大括号和其中的字符会被替换成传入str.format()的参数。大括号中的数值指明使用传入str.format()方法的对象中的哪一个。
旧式的字符串格式化
操作符%也可以用于字符串格式化。
文件读写
函数open()返回文件对象,通常的用法需要两个参数:open(filename,mode)
r |
只读 默认‘r’模式 |
w |
只写 |
r+ |
以读写的方式打开文件 |
a |
以追加的方式打开文件 |
文件对象方法
读取文件内容,需要调用f.read(size)
f.readline() #从文件中读取单独一行
f.readlines() #返回一个列表,其中包含了文件中所有的数据行。
f.write(string) #方法将string的内容写入文件,并返回写入字符的长度。
#想要写入其他非字符串内容,首先要将它转换成为字符串:
>>> f = open('/tmp/workfile','w')
>>> value = ('the answer',42)
>>> s = str(value)
>>> f.write(s)
f.tell() #返回一个整数,代表文件对象在文件中的指针位置,该数值计量了自文件开头到指针处的比特数。需要改变文件对象指针的话,使用 f.seek(offset,from_what).指针在该操作中从指定的引用位置移动offset比特,引用位置由from_what参数指定。from_what值为0表示自文件起始处开始,1表示自当前文件指针位置开始,2表示自文件末尾开始。from_what可以忽略,其默认值为零,此时从文件头开始。
#用关键字with处理文件对象是一个好习惯,它的先进之处在于文件用完后会自动关闭,就算发生异常也没有关系,他是try-finally快的简写。
>>> with open('/tmp/workfile','r') as f:
... read_data = f.read()
>>> f.closed
True
pickle模块
把python对象表达为字符串,这一过程称为封装,从字符串表达出重新构造对象称之为拆封,封装状态中的对象可以存储在文件会对象中。
#如果你有一个对象x,一个以写模式打开的文件对象f,封装对象的最简单的方法只需要一行代码:
pickle.dump(x,f)
#如果f是一个以读模式打开的文件对象,就可以重装拆封这个对象。
x = pickle.load(f)
错误和异常
python中至少有两种错误:语法错误和异常。
语法错误
语法错误,也被称作解析错误。
>>> while True print('hello world')
File "<stdin>", line 1
while True print('hello world')
^
SyntaxError: invalid syntax
语法分析器指出错误行,并且在检测到错误的位置前面显示一个小箭头,错误是由箭头前面的标记引起的(或者至少是这么检测的),这上面的例子中,函数print()被发现存在错误,因为它前面少了一个冒号(’:’)。错误会输出文件名和行号,所以如果是从脚本输入的你就知道去哪里检查错误了。
异常
运行期检测到的错误称为异常。并且程序不会无条件的崩溃。
错误信息的前半部分以堆栈的形式列出异常发生的位置,通常在堆栈中列出了源代码行,然而,来自标准输入的源码不会显示出来。
异常处理
通过编程处理选择的异常是可行的。
while True:
try:
x = int("please enter a number:")
break
except ValueError:
print("try again...")
try语句按如下方式工作
首先,执行try子句(在try和except关键字之间的部分)
如果没有发生异常,except子句在try语句执行完毕后就被忽略了