参考教程《python基础教程》 Magnus Lie Hetland
一、函数
1.函数定义:
函数定义的主要目的是代码重复使用,下边是定义的一个函数(生成斐波那契数列):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def fibs(n): 2 'generate Fibonacci sequence : n>2' 3 fibs = [0, 1] 4 for i in range(n-2): 5 fibs.append(fibs[-2] + fibs[-1]) 6 return fibs
第2行,放在函数开头的字符串称为文档字符串(docstring),可以使用 __doc__ 属性获取 。
要判断某个对象是否可调用,可使用内置函数callable。
特殊的内置函数help很有用。在交互式解释器中,可使用它获取有关函数的信息,其中包含函数的文档字符串。
下面是对该函数的一组命令行查看:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
>>> callable(fibs) True >>> help(fibs) >>> fibs.__doc__ 'generate Fibonacci sequence : n>2'
2.形参和实参:
字符串(以及数和元组)是不可变的(immutable),但是列表和字典是可变的。
下边的例子中,一个形参是字典(可变的),在函数中的操作可以修改参数(传入的参数字典是一个空字典)。
参数定义时,full_name='Jim Green' ,表示在调用这个函数时,这个参数可以不赋值,而这时会给参数默认值:'Jim Green' ,这点在参数使用时候是非常有用的。同时,这点也可以忽略掉顺序对参数的影响。这个也有个自己的名字叫关键字参数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def init_dic(data): 2 data['first'] = {} 3 data['middle'] = {} 4 data['last'] = {} 5 6 7 def lookup_name(data, label, name): 8 return data[label].get(name) 9 10 11 # 第二个参数full_name在调用该函数时,可以不输入。 12 def store(data, full_name='Jim Green'): 13 """ 14 :param data: 一个字典 15 :param full_name: 包含first_name、middle_name、last_name 16 :return: 将这个人名加入后返回这个字典 17 """ 18 names = full_name.split() 19 # 如果没有middle name,插入一个空串作为middle_name 20 if len(names) == 2 : names.insert(1, '') 21 labels = ['first', 'middle', 'last'] 22 for label, name in zip(labels, names): 23 people = lookup_name(data, label, name) 24 if people: 25 if full_name != people: 26 data[label].setdefault(name, []).append(full_name) 27 else: 28 print "already exists!!" 29 else: 30 data[label][name] = [full_name] 31 return data
下边是测试这几个函数的语句:
store_data = {} init_dic(store_data) store(store_data) # 测试使用默认值和顺序 # store(store_data, 'Robin Clark Jackson') # store(store_data, 'Robin Clark Pearson') print store_data
3.收集和分配参数:
参数前面的星号将提供的所有值都放在一个元组中,也就是将这些值收集起来。星号不会收集关键字参数。这项在参数数量不定时,非常有用。
要收集关键字参数,可使用两个星号,这样得到的是一个字典而不是元组。关键词参数可以使用**来收集起来。
请看下边的例子:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 >>> def print_params_4(x, y, z=3, *pospar, **keypar): 2 ... print(x, y, z) 3 ... print(pospar) 4 ... print(keypar) 5 ... 6 >>> print_params_4(1, 2, 3, 5, 6, 7, foo=1, bar=2) 7 (1, 2, 3) 8 (5, 6, 7) 9 {'foo': 1, 'bar': 2} 10 >>> print_params_4(1, 2) 11 (1, 2, 3) 12 () 13 {}
只有在定义函数(允许可变数量的参数)或调用函数时(拆分字典或序列)使用,星号才能发挥作用。
4.作用域:
其实,我们定义的所有的变量都存在一个“看不见的字典”中。例如,x = 1 表示定义变量x,并且指向值1,这很符合字典的定义,x就是key,而1是value。python有一个内置函数vars(),它返回这个看不见的“字典”。这种“看不见的字典”称为命名空间或作用域。每个函数调用都会创建一个命名空间。
在函数内部定义的变量称为局部变量,函数外边叫全局变量。在函数内部可以访问全局变量,但是如果有一个局部变量或参数与你要访问的全局变量同名,就无法直接访问全局变量,因为它被局部变量遮住了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 函数内部访问全局变量 2 >>> external = 'Japan' 3 >>> def printcountry(): 4 ... inner = 'China' 5 ... print (inner + external) 6 >>> printcountry() 7 ChinaJapan 8 9 #局部变量遮住全局变量 10 >>> external = 'Japan' 11 >>> def printcountry_1(): 12 ... inner = 'China' 13 ... external = 'USA' 14 ... print (inner + external) 15 ... 16 >>> printcountry_1() 17 ChinaUSA
在函数内部给变量赋值时,我们都是赋给了局部变量,如果我们想赋值给全局变量,该如何做呢?答案是使用global关键字。
下边例子中,在函数myChange中修改了全局变量x。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 >>> x = 9 2 >>> def myChange(): 3 ... global x 4 ... x = x*20 5 ... 6 >>> x 7 9 8 >>> myChange() 9 >>> x 10 180
另外,函数是可以嵌套定义的,也就是说,可以在一个函数的定义内再定义另外任意多个函数。
5.递归:
使用递归的优点是:在很多情况下,使用递归的可读性更高,且有时要高得多。递归函数的定义都要满足下面两个条件:
基线条件(针对最小的问题):满足这种条件时函数将直接返回一个值。
递归条件:包含一个或多个调用,这些调用旨在解决问题的一部分。
下面是一个非常典型的例子——使用递归方法实现“二分查找”。
Python提供了一些有助于进行这种函数式编程的函数:map、filter和reduce。例如,例子map(str,range(10)),使用map将序列的所有元素传递给函数。
将0-9的数字序列,传给了函数str,进而将它们转为了字符串。
>>> list(map(str, range(10))) # 与[str(i) for i in range(10)]等价 ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
二、类(自定义对象)
1.类定义:
从java得知,类的三个特性:继承、封装、多态。python也是面向对象编程语言,所以概念类似,下面简单定义了一个类。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 __metaclass__ = type # 在较旧的Python版本中,要创建新式类,应在脚本或模块开头放置赋值语句__metaclass__ = type,不加这个需要定义init方法。 2 3 4 class Person: 5 6 def setName(self, name): 7 self.name = name 8 9 def getName(self): 10 return self.name 11 12 def greeting(self): 13 print 'hello, I am {}'.format(self.name) 14 15 def __myownMethod(self): 16 print 'The method can not be accessed outer.'
我使用的是python 2 增加了开头这句:__metaclass__ = type 。 在上边的例子中参数self 指向对象本身。
方法和函数的区别表现在参数self上,方法将其第一个参数关联到它所属的实例,因此无需提供这个参数。调用这个方法时,不用写上self参数,而会自动传入。
要让方法或属性成为私有的(不能从外部访问),只需让其名称以两个下划线打头即可(例如上边例子中的__myownMethod方法)。这相当于java中的private ...定义的属性和方法,是私有的,只能在类内部访问。
2.继承和超类:
要指定超类,可在class语句中的类名后加上超类名,并将其用圆括号括起。
要确定一个类是否是另一个类的子类,可使用内置方法issubclass。
如果你有一个类,并想知道它的基类,可访问其特殊属性__bases__。
要确定对象是否是特定类的实例,可使用isinstance。
如果你要获悉对象属于哪个类,可使用属性__class__。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #!/bin/bash 2 # -*- encoding: utf-8 -*- 3 __metaclass__ = type 4 5 6 class Filter(): 7 def __init__(self): 8 self.blocked = [] 9 10 def filter(self, seq): 11 return [x for x in seq if x not in self.blocked] 12 13 14 class SPAMFilter(Filter): 15 def __init__(self): 16 self.blocked = ['SPAM'] 17 18 19 if __name__ == '__main__': 20 f = Filter() 21 f.__init__() 22 print f.filter([1, 2, 3, 4]) 23 s = SPAMFilter() 24 s.__init__() 25 print s.filter(['SPAM', 'SPAM', 'SPAM', 'SPAM', 'Lucifer', 'Cap']) 26 # issubclass的参数必须是类名。 27 print issubclass(SPAMFilter, Filter) 28 print SPAMFilter.__bases__ 29 print isinstance(s, SPAMFilter) 30 print s.__class__
python与java相比,一个重大的区别是可以多重继承。
三、异常
1.异常和抛出异常:
Python使用异常对象来表示异常状态,并在遇到错误时引发异常。异常对象未被处理(或捕获)时,程序将终止并显示一条错误消息(traceback)。
要引发异常,可使用raise语句,并将一个类(必须是Exception的子类)或实例作为参数。下表列出一些常见的异常类。
这些类都可以使用raise语句抛出异常:
>>> raise ValueError Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError
自定义异常:创建异常类和其他类很相似,只要直接或间接地继承Exception类即可,例如可以定义如下:class SomeCustomException(Exception): pass
2.捕获异常:
异常从函数向外传播到调用函数的地方。如果在这里也没有被捕获,异常将向程序的最顶层传播。这意味着你可使用try/except来捕获他人所编写函数引发的异常。
当然,你也可以在except环节,再次调用raise语句来抛出异常,那么异常还会向程序的上层传播。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def except_demo(): 2 try: 3 f1 = int(input("Please input 1st number:")) 4 f2 = int(input("Please input 2nd number:")) 5 f = f1/f2 6 print "The final output:{}".format(f) 7 except ZeroDivisionError: 8 print "Can't divided by zero."
捕获异常后,如果要重新引发它(即继续向上传播),可调用raise且不提供任何参数。
那么,上边的语句就是:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def except_demo(): 2 try: 3 f1 = int(input("Please input 1st number:")) 4 f2 = int(input("Please input 2nd number:")) 5 f = f1/f2 6 print "The final output:{}".format(f) 7 except ZeroDivisionError: 8 raise
在一个try语句块后,可以指定使用多个except语句来捕获多个异常,也可以使用一个except语句,并把多个异常放入一个元组内一起捕获。如果想将捕获的异常指定给一个变量,那么使用as e可以获取指向异常对象的变量e。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def except_demo_2(): 2 """ 3 同时捕获多个异常 4 :return: 5 """ 6 try: 7 f1 = int(input("Please input 1st number:")) 8 f2 = int(input("Please input 2nd number:")) 9 f = f1/f2 10 print "The final output:{}".format(f) 11 except ZeroDivisionError: 12 print ("Can not divided by zero!!") 13 except ValueError: 14 print ("The input type is not right!") 15 16 17 def except_demo_3(): 18 """ 19 同时捕获多个异常,同时使用元组在一个except语句中完成 20 :return: 21 """ 22 try: 23 f1 = int(input("Please input 1st number:")) 24 f2 = int(input("Please input 2nd number:")) 25 f = f1/f2 26 print "The final output:{}".format(f) 27 except (ZeroDivisionError, ValueError) as e: 28 print ("Input error!!") 29 print e
为了不让我们的程序崩溃,我们可以一次捕获所有的异常,可直接使用 except: 或者获取异常对象到e中:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def except_demo_4(): 2 """ 3 同时捕获多个异常,同时使用元组在一个except语句中完成 4 :return: 5 """ 6 try: 7 f1 = int(input("Please input 1st number:")) 8 f2 = int(input("Please input 2nd number:")) 9 f = f1/f2 10 print "The final output:{}".format(f) 11 except Exception as e: 12 print ("Input error!!") 13 print e
在try/except语句中,还可以加入else语句,和finnally语句。 else语句,是指如果不发生异常,将执行的内容。finally指不管是否发生异常,都将要执行的内容。
例如下边例子:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def except_demo_5(): 2 try: 3 1 / 2 4 except NameError: 5 print ("Unknown variable!!") 6 else: 7 print("went well") 8 finally: 9 print "cleanup"
如果不处理函数中引发的异常,它将向上传播到调用函数的地方。如果在那里也未得到处理,异常将继续传播,直至到达主程序(全局作用域)。如果主程序中也没有异常处理程序,程序将终止并显示栈跟踪消息。如果你只想发出警告,指出情况偏离了正轨,并不会让程序退出,可使用模块warnings中的函数warn。
>>> from warnings import warn >>> warn("Something warn!!") __main__:1: UserWarning: Something warn!! >>> warn("Something warn!!")
四、条件和循环
1.print和import:
print语句(在3之后称为print函数了)后边用逗号连接的多个字符串,会被合并成一个字符串,但是它们之间用逗号分隔。
>>> print ("Age:",42) ('Age:', 42) >>> print "Age:",42 Age: 42 >>> name = "McGr" >>> action = "swimming" >>> date = "today" >>> print name,action,date McGr swimming today >>> print name,",",action,date McGr , swimming today >>> print name+",",action,date McGr, swimming today
例如,看语句 print name,action,date 的返回结果。
如果不希望看到中间的空格,可以使用字符串相加的方式: 例如: print name+",",action,date
在引入模块时,可以使用as来将引入的模块重命名,例如,经常使用语句 : import pandas as pd