python基础学习笔记2

时间:2021-04-02 04:58:49
词典

 
词典(dictionary)与列表相似,也可以存储多个元素。存储多个元素的对象称为容器(container);

常见的创建词典的方法:

>>>dic = {'tom':11, 'sam':57,'lily':100}

>>>print type(dic)

与表类似,以逗号分隔每一个元素;每一个元素包含两个部分,键和值;(不可以变的对象可以作为键)。值可以是任意对象;键和值是一一对应;

 
与表不同的是,词典的元素没有顺序。你不能通过下标引用元素。词典是通过键来引用。
>>>print dic['tom']

>>>dic['tom'] = 30

>>>print dic

在词典中增添一个新元素的方法:

>>>dic['limi'] = 99

>>>print dic
这里,我们引用一个新的键,并赋予它对应的值。
 
词典元素的循环调用
dic = {'lilei': 90, 'lily': 100, 'sam': 57, 'tom': 90}
for key in dic:
print dic[key]

在循环中,dict的每个键,被提取出来,赋予给key变量。

通过print的结果,我们可以再次确认,dic中的元素是没有顺序的。
 
词典常用方法
>>>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))
文本文件的输入输出

 
创建文件对象

我们打开一个文件,并使用一个对象来表示该文件:

f = open(文件名,模式)
最常用的模式有:

"r"     # 只读

“w”     # 写入
比如
>>>f = open("test.txt","r")

具体用法需要在实践,这里只是简单的整体概括

 
模块

 
在Python中,一个.py文件就构成一个模块。通过模块,你可以调用其它文件中的程序。
 
引入模块
先写一个first.py文件,内容如下:
def laugh():
print 'HaHaHaHa'
再写一个second.py,并引入first中的程序:
import first
for i in range(10):
first.laugh()

在second.py中,我们使用了first.py中定义的laugh()函数。

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

上面例子中,first为引入的模块,laugh()是我们所引入的对象。

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可以是一个空文件。
 
函数参数

 
值传递
def f(a,b,c):
return a+b+c print(f(1,2,3))
在调用f时,1,2,3根据位置分别传递给了a,b,c。
 
关键字传递

有些情况下,用位置传递会感觉比较死板。关键字(keyword)传递是根据每个参数的名字传递参数。

关键字并不用遵守位置的对应关系。依然沿用上面f的定义,更改调用方式:

print(f(c=3,b=2,a=1)) 

关键字传递可以和位置传递混用。但位置参数要出现在关键字参数之前:

print(f(1,c=3,b=2))
参数默认值

在定义函数的时候,使用形如c=10的方式,可以给参数赋予默认值(default)。

如果该参数最终没有被传递值,将使用该默认值。

def f(a,b,c=10):
return a+b+c print(f(3,2))
print(f(3,2,1))

在第一次调用函数f时, 我们并没有足够的值,c没有被赋值,c将使用默认值10.

第二次调用函数的时候,c被赋值为1,不再使用默认值。
 
包裹传递
 
位置传递,其实传过去的是一个tuple

下面是包裹位置传递的例子:

def func(*name):
print type(name)
print name func(1,4,6)
func(5,6,7,1,2,3)

两次调用,尽管参数个数不同,都基于同一个func定义。在func的参数表中,所有的参数被name收集,根据位置合并成一个元组(tuple),这就是包裹位置传递。

为了提醒Python参数,name是包裹位置传递所用的元组名,在定义func时,在name前加*号。
 
下面是包裹关键字传递的例子:
其实是字典传递
def func(**dict):
print type(dict)
print dict func(a=1,b=9)
func(m=2,n=1,c=11)

与上面一个例子类似,dict是一个字典,收集所有的关键字,传递给函数func

。为了提醒Python,参数dict是包裹关键字传递所用的字典,在dict前加**。

包裹传递的关键在于定义函数时,在相应元组或字典前加*或**。
 
解包裹

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

def func(a,b,c):
print a,b,c args = (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。

 
循环设计

 
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()函数起到了聚合列表的功能。
解析zip():
>>> ta = [1,2,3]
>>> tb = [4,5,6]
>>> zipped = zip(ta,tb)
>>> print type(zipped)
<type 'list'>
>>> print zipped
[(1, 4), (2, 5), (3, 6)]
>>> print zipped[1]
(2, 5)
循环对象
 
循环对象是这样一个对象,它包含有一个next()方法(__next__()方法,在python 3x中), 这个方法的目的是进行到下一个结果,而在结束一系列结果之后,举出StopIteration错误。
 
例子:
假设我们有一个test.txt的文件:
1234
abcd
efg

我们运行一下python命令行:

>>>f = open('test.txt')

>>>f.next()

>>>f.next()

...
不断输入f.next(),直到最后出现StopIteration
open()返回的实际上是一个循环对象,包含有next()方法。而该next()方法每次返回的就是新的一行的内容,到达文件结尾时举出StopIteration。这样,我们相当于手工进行了循环。
 
自动的话:
for line in open('test.txt'):
print line
在这里,for结构自动调用next()方法,将该方法的返回值赋予给line。循环知道出现StopIteration的时候结束。
相对于序列,用循环对象的好处在于:不用在循环还没有开始的时候,就生成好要使用的元素。所使用的元素可以在循环过程中逐次生成。这样,节省了空间,提高了效率,编程更灵活。
 
 
异常处理

 
在项目开发中,异常处理是不可或缺的。异常处理帮助人们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 ' 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
 
总结

 
  • 词典
    • dic={'tom':11,'sam':57}
    • 增加元素
      • dic['limi']=99
    • 注意
      • key-value,在对key的操作都要引号无论是定义或者引用。
      • 且key的值是不可变的,value是可以变动的;
    • 字典元素循环调用
      • for key in dic:
    • 常用方法
      • >>> dic.keys()     # 返回dic所有的键
      • >>> dic.values()  # 返回dic所有的值
      • >>> dic.items()   # 返回dic所有的元素(键值对)
      • >>> dic.clear()    # 清空dic,dict变为{}
      • >>> del dic['tom']  # 删除 dic 的‘tom’元素
  • 文本文件输入输出
    • 创建文件对象
      • f = open(文件名,模式)
        • 模式
          • "r"     # 只读
          • “w” # 写入
  • 模块
    • 模块引用
      • import a as b
      • from a import function1
      • from a import *
    • 搜索模块的路径
      • - 程序所在的文件夹
      • - 标准库的安装路径
      • - 操作系统环境变量PYTHONPATH所包含的路径
    • 模块包
      • 将功能相似的模块放在同一文件夹中(如this_dir)构成模块包
        • import this_dir.module
        • 引入this_dir 文件夹中的module模块
      • this_dir中必须包含 __init__.py文件,告诉Python这是一个模块包。
  • 函数参数
    • 值传递
      • 根据位置关系
    • 关键字传递
      • 根据关键字名称
    • 参数默认值
      • 调用时可以不用传值,而是用默认值
    • 包裹传递
      • def func(*name):
        • func(1,4,6): 将数 1,4,6 传给name 作为一个tuple (1,4,6)
        • func(5,6,7,1,2): 将数5,6,7,1,2 传给name 作为一个tuple(5,6,7,1,2)
      • def func(**dict):
        • func(a=1,b=9):将数a=1,b=9 传给dict作为字典('a':1,'b':9)
      • 像是将数据打包一起传送,因此叫做包裹传递
    • 解包裹
      • def func(a,b):
        • args=(1,2)
          • func(*args)
          • 传递的时候,将一个tuple args 传过去变成 三个数
        • dict={'a':1,'b':2}
          • func(**dict)
          • 传递的时候,将字典 dict 传过去变成三个数
        • 注意,tuple 传是* ,dict传则是**
  • 循环设计
    • range()
      • 定义:上限,下限,步长
    • enumerate()
      • 返回下标以及值
    • zip()
      • 从多个列表中,依次各取出一个元素
    • for line in open('test.txt'):
  • 异常处理
    • try->异常->except->finally
    • try->无异常->else->finally