python基础学习

简介

龟叔 Guido van rossum

胶水语言

提供了非常完善的代码库

运行速度慢,大小写敏感

是解释型语言,也就是说,发布项目时相当于发布源代码

编译型语言,如C语言,运行以后生成exe文件,不能从exe文件反推出C语言代码

Python语言解释器:

​ CPython 使用广泛 >>>

​ IPython 基于CPython,在交互方式上有增强 In[序号]

​ PyPy 注重于执行速度,动态编译Python

​ JPython 编译为java字节码

​ IronPython 编译为.NET字节码

Python代码运行助手

​ 让浏览器运行Python代码

​ 源码:c:codespythonlearning.py

​ 方法:

​ 先将python保存为临时文件,然后调用解释器

语法

  1. 以 : 结尾的语句被视为一个代码块

    条件判断

    ​ if 条件:

    ​ 操作语句

    ​ elif 条件:

    ​ 操作语句

    ​ else:

    ​ 操作语句

    循环

    ​ for l in list:

    ​ 操作语句

    ​ while 条件:

    ​ 操作语句

    range(x,y,z)生成一个整数序列,可以通过list()转换成list数据类型;x代表开始数字,y代表结束数字,z代表隔z个数字取

  2. print("your name is %s" % name)

    占位符

    ​ %s 字符串

    ​ %d 整数

    ​ %f 浮点数

    ​ %x 十六进制整数

    ​ %%=%

    整数、浮点数没有大小限制,浮点数超出一定范围直接表示为inf(无限大)、

list与tuple数组

tuple和list的主要区别在于,一旦建立,tuple的各个元素不可再变更,而list的各个元素可以再变更

tuple 元组/定值表

>>>s1 = (2, 1.3, 'love', 5.6, 9, 12, False)         # s1是一个tuple     
>>>s2 = [True, 5, 'smile']                          # s2是一个list

list可变数组 list=[]

​ list.append(str) 追加元素

​ list.insert(index,str) 将字符串插入到指定索引位置

​ list.pop() 删除list末尾元素

​ list.pop(index) 删除指定索引位置的元素

​ list里最后一个字符,索引位置的使用 -1,len(list)-1

tuple数组定长 tuple=()

​ 当tuple数组里只有一个元素时,t=(1,)

范围引用: 基本样式[下限:上限:步长]

>>>print(s1[:5])             # 从开始到下标4 (下标5的元素 不包括在内)

>>>print(s1[2:])             # 从下标2到最后

>>>print(s1[0:5:2])          # 从下标0到下标4 (下标5不包括在内),每隔2取一个元素 (下标为0,2,4的元素)

>>>print(s1[2:0:-1])         # 从下标2到下标1

从上面可以看到,在范围引用的时候,如果写明上限,那么这个上限本身不包括在内。

尾部元素引用

>>>print(s1[-1])             # 序列最后一个元素

>>>print(s1[-3])             # 序列倒数第三个元素

同样,如果s1[0:-1], 那么最后一个元素不会被引用 (再一次,不包括上限元素本身)

词典

词典和表类似的地方,是包含有多个元素,每个元素以逗号分隔。但词典的元素包含有两部分,键和值,常见的是以字符串来表示键,也可以使用数字或者真值来表示键(不可变的对象可以作为键)。值可以是任意对象。键和值两者一一对应。

与表不同的是,词典的元素没有顺序。你不能通过下标引用元素。词典是通过键来引用。

dic = {'tom':11, 'sam':57,'lily':100}
#在词典中增添一个新元素的方法:
>>>dic['lilei'] = 99
>>>print dic
#词典的循环调用
dic = {'lilei': 90, 'lily': 100, 'sam': 57, 'tom': 90}
for key in dic:
    print dic[key]
#常用方法
>>>print dic.keys()           # 返回dic所有的键
>>>print dic.values()         # 返回dic所有的值
>>>print dic.items()          # 返回dic所有的元素(键值对)
>>>dic.clear()                # 清空dic,dict变为{}
#另外有一个很常用的用法:
>>>del dic['tom']             # 删除 dic 的‘tom’元素
#del是Python中保留的关键字,用于删除对象。
#与表类似,你可以用len()查询词典中的元素总数。
>>>print(len(dic))
  1. sorted函数按key值对字典排序

​ 先来基本介绍一下sorted函数,sorted(iterable,key,reverse),sorted一共有iterable,key,reverse这三个参数。

​ 其中iterable表示可以迭代的对象,例如可以是 dict.items()、dict.keys()等,key是一个函数,用来选取参与比较的元素,reverse则是用来指定排序是倒序还是顺 序,reverse=true则是倒序,reverse=false时则是顺序,默认时reverse=false。

​ 要按key值对字典排序,则可以使用如下语句:

d={"a":1,"f":3,"e":1,"b":7}
sorted(d.keys())     #["a","b","e","f"]

​ 直接使用sorted(d.keys())就能按key值对字典排序,这里是按照顺序对key值排序的,如果想按照倒序排序的话,则只要将reverse置为true即可。

  1. sorted函数按value值对字典排序

​ 要对字典的value排序则需要用到key参数,在这里主要提供一种使用lambda表达式的方法,如下:

d={"a":1,"f":3,"e":1,"b":7}
sorted(d.items(),key=lambda item:item[1])     #[("a",1),("b",7),("e",1),("f",3)]

这里的d.items()实际上是将d转换为可迭代对象,迭代对象的元素为 ("a",1),("b",7),("e",1),("f",3),items()方法将字典的元素 转化为了元组,而这里key参数对应的lambda表达式的意思则是选取元组中的第二个元素作为比较参数(如果写作key=lambda item:item[0]的话则是选取第一个元素作为比较对象,也就是key值作为比较对象。lambda x:y中x表示输出参数,y表示lambda 函数的返回值),所以采用这种方法可以对字典的value进行排序。注意排序后的返回值是一个list,而原字典中的名值对被转换为了list中的元组。

列表、阵列

color=['red','green','blue']  
print(color[0])  
color.append('orange') # red,green,blue,orange  
c=color.pop(1); # 索引为1的元素弹出,并将其赋值给c  
print(c) # green  
print(color)  
color.append(['white','black']) # 添加一项类型为列表的元素['white','black']  
print(color)  # ['red', 'blue', 'orange', ['white', 'black']]  
del color[3] # 将其删除  
print(color) #['red', 'blue', 'orange']  
color=color+['white','black'] # color列表与['white','black'] 合并并重新赋值给color  
print(color) #['red', 'blue', 'orange', 'white', 'black']    

请注意上面的color.append(['white','black'])和color=color+['white','black']的区别

  1. 动态生成列表:

    a=[x for x in range(1,11,1)]  
    print(a) #[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]      
    
  2. 列表的复制 :

    newcopy=data[:]

    列表中套列表即可形成阵列(听起来是不是很牛X?),比如下面, r就是阵列:

    r1=[1,2,3,4,5]  
    r2=[10,20,30,40,50]  
    r3=[100,200,300,400,500]  
    arr=[r1,r2,r3]  
    for row in arr:   
        print(row)   
    
  3. 阵列的操作,比如列提取,行统计

    m=[[1,2,3],[2,3,50],[33,20,30]]  
    n=[row[1]for row in m if row[2]>10]  
    print(n)  
    
    r1=[  1,  2,  3,  4,  5]  
    r2=[ 10, 20, 30, 40, 50]  
    r3=[100,200,300,400,500]  
    arr=[r1,r2,r3]  
    for row in arr:   
        print(row)  
      
    #阵列操作  
    c1=[row[0] for row in arr] #将arr阵列的每行的第1个单元取出,并组成列表后赋值给c1 ,c1是列表类型  
    print(c1) #[1, 10, 100]  
    c11=[row[0]+50 for row in arr] #将arr阵列的每行的第1个单元取出后分别加50后的值组成列表后赋给c11 ,c11是列表类型  
    print(c11)  
    
      
    c2=[row[1] for row in arr if row[1]>=20] #添加条件的取值: 每行第2个元素>=20才考虑  
    print (c2) # [20, 200]  
    #统计阵列中每行的总数  
    s=(sum(row) for row in arr) #创建一个逐行统计的生成器  
    i=0  
    while (i<len(arr)):  
        print ("Line %d, sum=%d" %(i , next(s)))   
        i=i+1      
    
  4. 统计阵列的总数:

    #统计这个阵列的总数  
    line_sum=list(map(sum,arr)) #将arr阵列每行统计数转换成一个列表赋值给line_sum  
    print(line_sum)# [15, 150, 1500]  
    print(sum(line_sum)) #再将每行的统计数再汇总输出:1665 
    

内置函数

秉承着一切皆对象的理念,我们再次回头来看函数(function)。函数也是一个对象,具有属性(可以使用dir()查询)。作为对象,它还可以赋值给其它对象名,或者作为参数传递。

lambda函数

在展开之前,我们先提一下lambda函数。可以利用lambda函数的语法,定义函数。lambda例子如下:

func = lambda x,y: x + y
print func(3,4)

lambda生成一个函数对象。该函数参数为x,y,返回值为x+y。函数对象赋给func。func的调用与正常函数无异。

以上定义可以写成以下形式:

def func(x, y):
    return x + y

函数作为参数传递

函数可以作为一个对象,进行参数传递。函数名(比如func)即该对象。比如说:

def test(f, a, b):
    print 'test'
    print f(a, b)

test(func, 3, 5)

test函数的第一个参数f就是一个函数对象。将func传递给f,test中的f()就拥有了func()的功能。

我们因此可以提高程序的灵活性。可以使用上面的test函数,带入不同的函数参数。比如:

test((lambda x,y: x**2 + y), 6, 9)

map()函数

map()是Python的内置函数。它的第一个参数是一个函数对象。

re = map((lambda x: x+3),[1,3,5,6])

这里,map()有两个参数,一个是lambda所定义的函数对象,一个是包含有多个元素的表。map()的功能是将函数对象依次作用于表的每一个元素,每次作用的结果储存于返回的表re中。map通过读入的函数(这里是lambda函数)来操作数据(这里“数据”是表中的每一个元素,“操作”是对每个数据加3)。

在Python 3.X中,map()的返回值是一个循环对象。可以利用list()函数,将该循环对象转换成表。

如果作为参数的函数对象有多个参数,可使用下面的方式,向map()传递函数参数的多个参数:

re = map((lambda x,y: x+y),[1,2,3],[6,7,9])

map()将每次从两个表中分别取出一个元素,带入lambda所定义的函数。

filter()函数

filter函数的第一个参数也是一个函数对象。它也是将作为参数的函数对象作用于多个元素。如果函数对象返回的是True,则该次的元素被储存于返回的表中。filter通过读入的函数来筛选数据。同样,在Python 3.X中,filter返回的不是表,而是循环对象。

filter函数的使用如下例:

def func(a):
    if a > 100:
        return True
    else:
        return False

print filter(func,[10,56,101,500])

reduce()函数

reduce函数的第一个参数也是函数,但有一个要求,就是这个函数自身能接收两个参数。reduce可以累进地将函数作用于各个参数。如下例:

print reduce((lambda x,y: x+y),[1,2,5,7,9])

reduce的第一个参数是lambda函数,它接收两个参数x,y, 返回x+y。

reduce将表中的前两个元素(1和2)传递给lambda函数,得到3。该返回值(3)将作为lambda函数的第一个参数,而表中的下一个元素(5)作为lambda函数的第二个参数,进行下一次的对lambda函数的调用,得到8。依次调用lambda函数,每次lambda函数的第一个参数是上一次运算结果,而第二个参数为表中的下一个元素,直到表中没有剩余元素。

上面例子,相当于(((1+2)+5)+7)+9

reduce()函数在3.0里面不能直接用的,它被定义在了functools包里面,需要引入包。

range()

在Python中,for循环后的in跟随一个序列的话,循环每次使用的序列元素,而不是序列的下标。

之前我们已经使用过range()来控制for循环。现在,我们继续开发range的功能,以实现下标对循环的控制:

S = 'abcdefghijk'
for i in range(0,len(S),2):
    print S[i]

在该例子中,我们利用len()函数和range()函数,用i作为S序列的下标来控制循环。在range函数中,分别定义上限,下限和每次循环的步长。这就和C语言中的for循环相类似了。

enumerate()

利用enumerate()函数,可以在每次循环中同时得到下标和元素:

S = 'abcdefghijk'
for (index,char) in enumerate(S):
    print index
    print char

实际上,enumerate()在每次循环中,返回的是一个包含两个元素的定值表(tuple),两个元素分别赋予index和char

zip()

如果你多个等长的序列,然后想要每次循环时从各个序列分别取出一个元素,可以利用zip()方便地实现:

ta = [1,2,3]
tb = [9,8,7]
tc = ['a','b','c']
for (a,b,c) in zip(ta,tb,tc):
    print(a,b,c)

每次循环时,从各个序列分别从左到右取出一个元素,合并成一个tuple,然后tuple的元素赋予给a,b,c

zip()函数的功能,就是从多个列表中,依次各取出一个元素。每次取出的(来自不同列表的)元素合成一个元组,合并成的元组放入zip()返回的列表中。zip()函数起到了聚合列表的功能。

我们可以分解聚合后的列表,如下:

ta = [1,2,3]
tb = [9,8,7]
# cluster
zipped = zip(ta,tb)
print(zipped)# decomposena, nb = zip(*zipped)print(na, nb)

abs()&hex()

abs()返回绝对值

hex()返回十六进制数

转换数据类型:int() float() str() bool()

在解释器中,导入一个python文件里的函数

from abstest import my_abs
rag_abs(-5)  

较小的精度

基础

浮点数是用机器上浮点数的本机双精度(64 bit)表示的。提供大约17位的精度范围从-308到308的指数。和C语言里面的double类型相同。Python不支持32bit的单精度浮点数。如果程序需要精确控制区间和数字精度,可以考虑使用numpy扩展库。

Python 3.X对于浮点数默认的是提供17位数字的精度。

关于单精度和双精度的通俗解释:

  • 单精度型和双精度型,其类型说明符为float 单精度说明符

  • double 双精度说明符。在Turbo C中单精度型占4个字节(32位)内存空间,其数值范围为3.4E-38~3.4E+38,只能提供七位有效数字。

  • 双精度型占8 个字节(64位)内存空间,其数值范围为1.7E-308~1.7E+308,可提供16位有效数字。

要求较小的精度

将精度高的浮点数转换成精度低的浮点数。

round()内置方法

这个是使用最多的,刚看了round()的使用解释,也不是很容易懂。round()不是简单的四舍五入的处理方式。

For the built-in types supporting round(), values are rounded to the closest multiple of 10 to the power minus ndigits; if two multiples are equally close, rounding is done toward the even choice (so, for example, both round(0.5) and round(-0.5) are 0, and round(1.5) is 2).

>>> round(2.5)
2
>>> round(1.5)
2
>>> round(2.675)
3
>>> round(2.675, 2)
2.67

round()如果只有一个数作为参数,不指定位数的时候,返回的是一个整数,而且是最靠近的整数(这点上类似四舍五入)。但是当出现.5的时候,两边的距离都一样,round()取靠近的偶数,这就是为什么round(2.5) = 2。当指定取舍的小数点位数的时候,一般情况也是使用四舍五入的规则,但是碰到.5的这样情况,如果要取舍的位数前的小树是奇数,则直接舍弃,如果偶数这向上取舍。看下面的示例:

>>> round(2.635, 2)
2.63
>>> round(2.645, 2)
2.65
>>> round(2.655, 2)
2.65
>>> round(2.665, 2)
2.67
>>> round(2.675, 2)
2.67
使用格式化

效果和round()是一样的。

>>> a = ("%.2f" % 2.635)
>>> a
'2.63'
>>> a = ("%.2f" % 2.645)
>>> a
'2.65'
>>> a = int(2.5)
>>> a
2
要求超过17位的精度分析

python默认的是17位小数的精度,但是这里有一个问题,就是当我们的计算需要使用更高的精度(超过17位小数)的时候该怎么做呢?

使用格式化(不推荐)
>>> a = "%.30f" % (1/3)
>>> a
'0.333333333333333314829616256247'

可以显示,但是不准确,后面的数字往往没有意义。

decimal+getcontext

高精度使用decimal模块,配合getcontext

>>> from decimal import *
>>> print(getcontext())
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])
>>> getcontext().prec = 50
>>> b = Decimal(1)/Decimal(3)
>>> b
Decimal('0.33333333333333333333333333333333333333333333333333')
>>> c = Decimal(1)/Decimal(17)
>>> c
Decimal('0.058823529411764705882352941176470588235294117647059')
>>> float(c)
0.058823529411764705

默认的context的精度是28位,可以设置为50位甚至更高,都可以。这样在分析复杂的浮点数的时候,可以有更高的自己可以控制的精度。其实可以留意下context里面的这rounding=ROUND_HALF_EVEN 参数。ROUND_HALF_EVEN, 当half的时候,靠近even.

小数和取整

既然说到小数,就必然要说到整数。一般取整会用到这些函数:

round()

这个不说了,前面已经讲过了。一定要注意它不是简单的四舍五入,而是ROUND_HALF_EVEN的策略。

math模块的ceil(x)

取大于或者等于x的最小整数。

math模块的floor(x)

去小于或者等于x的最大整数.

>>> from math import ceil, floor
>>> round(2.5)
2
>>> ceil(2.5)
3
>>> floor(2.5)
2
>>> round(2.3)
2
>>> ceil(2.3)
3
>>> floor(2.3)
2
>>>

生成器

生成器(generator)的主要目的是构成一个用户自定义的循环对象。

生成器的编写方法和函数定义类似,只是在return的地方改为yield。生成器中可以有多个yield。当生成器遇到一个yield时,会暂停运行生成器,返回yield后面的值。当再次调用生成器的时候,会从刚才暂停的地方继续运行,直到下一个yield。生成器自身又构成一个循环器,每次循环使用一个yield返回的值。

下面是一个生成器:

def gen():
    a = 100
    yield a
    a = a*8
    yield a
    yield 1000

该生成器共有三个yield, 如果用作循环器时,会进行三次循环。

for i in gen():
    print i

再考虑如下一个生成器:

def gen():
    for i in range(4):
        yield i

它又可以写成生成器表达式(Generator Expression):

G = (x for x in range(4))

生成器表达式是生成器的一种简便的编写方式。

测试代码:

def gen():
    for i in range(4):
        yield i
        
for i in gen():
    print i

G = (x for x in range(4))
for i in G:
    print(i)

表推导

表推导(list comprehension)是快速生成表的方法。它的语法简单,很有实用价值。

假设我们生成表L:

L = []
for x in range(10):
    L.append(x**2)

以上产生了表L,但实际上有快捷的写法,也就是表推导的方式:

L = [x**2 for x in range(10)]

这与生成器表达式类似,只不过用的是中括号。

自定义函数

对于基本数据类型的变量,变量传递给函数后,函数会在内存中复制一个新的变量,从而不影响原来的变量。(我们称此为值传递)

但是对于表来说,表传递给函数的是一个指针,指针指向序列在内存中的位置,在函数中对表的操作将在原有内存中进行,从而影响原有变量。 (我们称此为指针传递)

自定义函数

​ def 函数名(参数列表):

​ 函数内容

​ return = return none

空函数:

def pop():
    pass   #占位符,让程序先运行起来

函数可以返回多个值,这多个值作为一个tuple返回,这个tuple也可以按照位置赋值给多个变量

数据类型检查

def my_abs(x):
	if not isinstance(x,(int,float)):           #isinstance(x,数据类型)判断x是否为该数据类型
		raise TypeError('bad operand type')
	if x>0:
		return x
	if x<0:
		return -x

函数的参数列表:

  • 正常定义的必选参数
  • 默认参数
  • 可变参数
  • 关键字参数
  • 命名关键字参数

默认参数

设置参数的默认值 如:def power(x,y=2)
必选参数在前;变化大的在前
调用默认参数:
正常传参,顺序调用;
不按顺序调用,要用参数名 如

enroll('Adam','M',city='tianjin')
def enroll(name,sex,age=18,city='beijing')
多次调用默认参数函数时的异常情况:

    def app_end(L=[]):
         L.append('END')
         return L                     #多次调用后L=['END','END',...]
     def app_end(L=None):
         if L is None:
             L=[]
         L.append('END')
         return L                     #多次调用后L=['END']

可变参数

def calc(numbers):
调用 calc(1,2,3,4) #调用时可任意传参,甚至0个参数
def calc(numbers):
调用 calc([1,2,3]) calc((1,2,3)) #只能传入list/tuple
如果将list/tuple作为参数 calc(
list/*tuple)

def func(**dict):
    print type(dict)
    print dict

func(a=1,b=9)
func(m=2,n=1,c=11)关键字参数

可变参数

传入0/多个参数,传入时自动组装成tuple

关键字参数

传入0/多个含参数名的参数,自动组装成dictionary

命名关键字参数

可以有缺省值
def person(name,age,,city,job)
def person(name,age,
city,job)
如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*
* 分隔符,*后均为命名关键字参数,限制传入的关键字参数;
可替换为一个可变参数

解包裹

*和**,也可以在调用的时候使用,即解包裹(unpacking), 下面为例:

def func(a,b,c):
    print a,b,cargs = (1,3,4)func(*args)

在这个例子中,所谓的解包裹,就是在传递tuple时,让tuple的每一个元素对应一个位置参数。在调用func时使用*,是为了提醒Python:我想要把args拆成分散的三个元素,分别传递给a,b,c。(设想一下在调用func时,args前面没有*会是什么后果?)

相应的,也存在对词典的解包裹,使用相同的func定义,然后:

dict = {'a':1,'b':2,'c':3}
func(**dict)

在传递词典dict时,让词典的每个键值对作为一个关键字传递给func。

参数定义的顺序:必选,默认,可变,命名关键字,关键字

递归函数

​ 函数调用是通过栈(stack)这种数据结构实现的

​ 调用一次,栈加一层栈帧

​ 函数返回,栈减一层栈帧

​ 递归次数过多,有可能栈溢出,可以用尾递归方法(尚未理解尾递归)

for循环遍历list/tuple 相当于迭代函数

判断是否为可迭代对象:

  • from collections import Iterable
  • isinstance('abc',Iterable)

可以用enumerate(list) 将list转换为索引元素

for i,value in enumerate([1,2,3]):
	print(i,value)

​ 输出结果:0 1 1 2 2 3

特殊方法

_init_()

_init_()是一个特殊方法(special method)。Python有一些特殊方法。Python会特殊的对待它们。特殊方法的特点是名字前后有两个下划线。

如果你在类中定义了_init_()这个方法,创建对象时,Python会自动调用这个方法。这个过程也叫初始化。

class happyBird(Bird):
    def __init__(self,more_words):
        print 'We are happy birds.',more_words

summer = happyBird('Happy,Happy!')

dir()&help()

两个内置函数,dir()和help()

dir()用来查询一个类或者对象所有属性。你可以尝试一下

>>>print dir(list)

help()用来查询的说明文档。你可以尝试一下

>>>print help(list)

(list是Python内置的一个类,对应于我们之前讲解过的列表)

类和对象

Python使用类(class)和对象(object),进行面向对象(object-oriented programming,简称OOP)的编程。

面向对象的最主要目的是提高程序的重复使用性。

class Bird(object):
    have_feather = True
    way_of_reproduction = 'egg'
    def move(self, dx, dy):
        position = [0,0]
        position[0] = position[0] + dx
        position[1] = position[1] + dy
        return position

summer = Bird()
print 'after move:',summer.move(5,8)

class Chicken(Bird):
    way_of_move = 'walk'
    possible_in_KFC = True

class Oriole(Bird):
    way_of_move = 'fly'
    possible_in_KFC = False

summer = Chicken()
print summer.have_feather
print summer.move(5,8)

在类定义时,括号里为了Bird。这说明,Chicken是属于鸟类(Bird)的一个子类,即Chicken继承自Bird。自然而然,Bird就是Chicken的父类。Chicken将享有Bird的所有属性

class Bird(object):
    have_feather = True
    way_of_reproduction  = 'egg'

括号中的object,当括号中为object时,说明这个类没有父类(到头了)

文件读写

Python具有基本的文本文件读写功能。Python的标准库提供有更丰富的读写功能。

文本文件的读写主要通过open()所构建的文件对象来实现。

f = open(文件名,模式)

最常用的模式有:

"r" # 只读

"w" # 写入

>>>f = open("test.txt","r")  

读取:

content = f.read(N)          # 读取N bytes的数据
content = f.readline()       # 读取一行
content = f.readlines()      # 读取所有行,储存在列表中,每个元素是一行。  

写入:

f.write('I like apple')      # 将'I like apple'写入文件  

关闭文件:

f.close()  

模块

引入模块后,可以通过模块.对象的方式来调用引入模块中的某个对象。

Python中还有其它的引入方式,

import a as b             # 引入模块a,并将模块a重命名为b
from a import function1   # 从模块a中引入function1对象。调用a中对象时,我们不用再说明模块,即直接使用function1,而不是a.function1。
from a import *           # 从模块a中引入所有对象。调用a中对象时,我们不用再说明模块,即直接使用对象,而不是a.对象。

搜索路径

Python会在以下路径中搜索它想要寻找的模块:

  1. 程序所在的文件夹
  2. 标准库的安装路径
  3. 操作系统环境变量PYTHONPATH所包含的路径

如果你有自定义的模块,或者下载的模块,可以根据情况放在相应的路径,以便Python可以找到。

模块包

可以将功能相似的模块放在同一个文件夹(比如说this_dir)中,构成一个模块包。通过

import this_dir.module

引入this_dir文件夹中的module模块。

该文件夹中必须包含一个__init__.py的文件,提醒Python,该文件夹为一个模块包。_init_.py可以是一个空文件。

异常处理

处理异常

在项目开发中,异常处理是不可或缺的。异常处理帮助人们debug,通过更加丰富的信息,让人们更容易找到bug的所在。异常处理还可以提高程序的容错性。

我们之前在讲循环对象的时候,曾提到一个StopIteration的异常,该异常是在循环对象穷尽所有元素时的报错。

我们以它为例,来说明基本的异常处理。

一个包含异常的程序:

re = iter(range(5))

for i in range(100):
    print re.next()

print 'HaHaHaHa'

首先,我们定义了一个循环对象re,该循环对象将进行5次循环,每次使用序列的一个元素。

在随后的for循环中,我们手工调用next()函数。当循环进行到第6次的时候,re.next()不会再返回元素,而是抛出(raise)StopIteration的异常。整个程序将会中断。

我们可以修改以上异常程序,直到完美的没有bug。但另一方面,如果我们在写程序的时候,知道这里可能犯错以及可能的犯错类型,我们可以针对该异常类型定义好”应急预案“。

re = iter(range(5))

try:
    for i in range(100):
        print re.next()
except StopIteration:
    print 'here is end ',i

print 'HaHaHaHa'

在try程序段中,我们放入容易犯错的部分。我们可以跟上except,来说明如果在try部分的语句发生StopIteration时,程序该做的事情。如果没有发生异常,则except部分被跳过。

随后,程序将继续运行,而不是彻底中断。

完整的语法结构如下:

try:
    ...
except exception1:
    ...
except exception2:    ...except:
    ...
else:
    ...
finally:
    ...

如果try中有异常发生时,将执行异常的归属,执行except。异常层层比较,看是否是exception1, exception2...,直到找到其归属,执行相应的except中的语句。如果except后面没有任何参数,那么表示所有的exception都交给这段程序处理。比如:

try:
    print(a*2)
except TypeError:
    print("TypeError")
except:
    print("Not Type Error & Error noted")

由于a没有定义,所以是NameError。异常最终被except:部分的程序捕捉。

如果无法将异常交给合适的对象,异常将继续向上层抛出,直到被捕捉或者造成主程序报错。比如下面的程序

def test_func():
    try:
        m = 1/0
    except NameError:
        print("Catch NameError in the sub-function")

try:
    test_func()
except ZeroDivisionError:
    print("Catch error in the main program")

子程序的try...except...结构无法处理相应的除以0的错误,所以错误被抛给上层的主程序。

如果try中没有异常,那么except部分将跳过,执行else中的语句。

finally是无论是否有异常,最后都要做的一些事情。

流程如下,

try->异常->except->finally

try->无异常->else->finally

抛出异常

我们也可以自己写一个抛出异常的例子:

print 'Lalala'
raise StopIteration
print 'Hahaha'

这个例子不具备任何实际意义。只是为了说明raise语句的作用。

StopIteration是一个类。抛出异常时,会自动有一个中间环节,就是生成StopIteration的一个对象。Python实际上抛出的,是这个对象。当然,也可以自行生成对象:

raise StopIteration()
原文地址:https://www.cnblogs.com/fengzzi/p/10042824.html