002-python函数、高级特性
1、函数1.1 定义函数在Python中,定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回 自定义一个求绝对值的my_abs函数为例:
def my_abs(x): 1.2 函数调用如果已经把my_abs()的函数定义保存为abstest.py文件了,那么,可以在该文件的当前目录下启动Python解释器,用from abstest import my_abs来导入my_abs()函数 def nop(): pass 参数类型检查 def my_abs(x): if not isinstance(x,(int,float)): raise TypeError(‘bad operand type‘) if x >= 0: return x else: return -x 函数返回多个值 import math def move(x,y,step,angle=0): nx = x + step * math.cos(angle) ny = y - step * math.sin(angle) return nx,ny 1.3 函数的参数1.3.1 位置参数 def power(x): return x * x 把power(x)修改为power(x,n),用来计算xn def power(x,n): s = 1 while n > 0: n = n - 1 s = s * x return s 修改后的power(x,n)函数有两个参数:x和n,这两个参数都是位置参数,调用函数时,传入的两个值按照位置顺序依次赋给参数x和n 1.3.2 默认参数 def power(x,n=2): s = 1 while n > 0: n = n - 1 s = s * x return s 设置默认参数时,需要注意的点 def enroll(name,gender): print(‘name:‘,name) print(‘gender:‘,gender) 继续传入年龄、城市等信息,我们可以把年龄和城市设为默认参数 def enroll(name,gender,age=6,city=‘Beijing‘): print(‘name:‘,name) print(‘gender:‘,gender) print(‘age:‘,age) print(‘city:‘,city) 只有与默认参数不符的学生才需要提供额外的信息 enroll(‘Bob‘,‘M‘,7) enroll(‘Adam‘,city=‘Tianjin‘) 有多个默认参数时,调用的时候,既可以按顺序提供默认参数 def add_end(L=[]): L.append(‘END‘) return L 使用默认参数调用时,一开始结果也是对的,但是,再次调用add_end()时,结果就不对了 >>> add_end() [‘END‘] >>> add_end() [‘END‘,‘END‘] 原因解释如下: def add_end(L=None): if L is None: L = [] L.append(‘END‘) return L 现在,无论调用多少次,都不会有问题 >>> add_end() [‘END‘] >>> add_end() [‘END‘] 1.3.3 可变参数 def calc(numbers): sum = 0 for n in numbers: sum = sum + n * n return sum 但是调用的时候,需要先组装出一个list或tuple: >>> calc([1,2,3]) 14 >>> calc((1,3,5,7)) 84 我们把函数的参数改为可变参数 def calc(*numbers): sum = 0 for n in numbers: sum = sum + n * n return sum 利用可变参数,调用函数的方式可以简化成这样: >>> calc(1,3) 14 >>> calc(1,7) 84 定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数 >>> nums = [1,3] >>> calc(*nums) 14 等价于 >>> nums = [1,3] >>> calc(nums[0],nums[1],nums[2]) 14 1.3.4 关键字参数 请看示例: def person(name,age,**kw): print(‘name:‘,name,‘age:‘,‘other:‘,kw) 在调用该函数时,可以只传入必选参数,也可以传入任意个数的关键字参数 >>> person(‘Michael‘,30) name: Michael age: 30 other: {} >>> person(‘Bob‘,35,city=‘Beijing‘) name: Bob age: 35 other: {‘city‘: ‘Beijing‘} >>> person(‘Adam‘,45,gender=‘M‘,job=‘Engineer‘) name: Adam age: 45 other: {‘gender‘: ‘M‘,‘job‘: ‘Engineer‘} 关键字参数可以扩展函数的功能。比如,在person函数里,我们保证能接收到name和age这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。 >>> extra = {‘city‘: ‘Beijing‘,‘job‘: ‘Engineer‘} >>> person(‘Jack‘,24,**extra) name: Jack age: 24 other: {‘city‘: ‘Beijing‘,‘job‘: ‘Engineer‘} **extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra 1.3.5 命名关键字参数 def person(name,*,city,job): print(name,job) 和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数 >>> person(‘Jack‘,city=‘Beijing‘,job=‘Engineer‘) Jack 24 Beijing Engineer 如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了 def person(name,*args,args,job) 命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错 def person(name,*,city=‘Beijing‘,job): print(name,job) >>> person(‘Jack‘,job=‘Engineer‘) Jack 24 Beijing Engineer 1.3.6 参数组合 def f1(a,b,c=0,*args,**kw): print(‘a =‘,a,‘b =‘,‘c =‘,c,‘args =‘,‘kw =‘,kw) def f2(a,d,‘d =‘,‘kw =‘,kw) 在函数调用的时候,Python解释器自动按照参数位置和参数名把对应的参数传进去 a = 1 b = 2 c = 0 args = () kw = {} >>> f1(1,c=3) a = 1 b = 2 c = 3 args = () kw = {} >>> f1(1,‘a‘,‘b‘) a = 1 b = 2 c = 3 args = (‘a‘,‘b‘) kw = {} >>> f1(1,‘b‘,x=99) a = 1 b = 2 c = 3 args = (‘a‘,‘b‘) kw = {‘x‘: 99} >>> f2(1,d=99,ext=None) a = 1 b = 2 c = 0 d = 99 kw = {‘ext‘: None} 通过一个tuple和dict,也可以调用上述函数 >>> args = (1,4) >>> kw = {‘d‘: 99,‘x‘: ‘#‘} >>> f1(*args,**kw) a = 1 b = 2 c = 3 args = (4,) kw = {‘d‘: 99,‘x‘: ‘#‘} >>> args = (1,3) >>> kw = {‘d‘: 88,‘x‘: ‘#‘} >>> f2(*args,**kw) a = 1 b = 2 c = 3 d = 88 kw = {‘x‘: ‘#‘} 小结 1.4 递归函数如果一个函数在内部调用自身本身,这个函数就是递归函数 def fact(n): if n==1: return 1 return n * fact(n - 1) 小结 2、高级特性2.1切片取一个list或tuple的部分元素是非常常见的操作。比如,一个list如下 >>> L = [‘Michael‘,‘Sarah‘,‘Tracy‘,‘Bob‘,‘Jack‘] L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3。即索引0,1,2,正好是3个元素 >>> L[0:3] [‘Michael‘,‘Tracy‘] 如果第一个索引是0,还可以省略 >>> L[:3] [‘Michael‘,‘Tracy‘] 按每两个取一个 >>> L[::2] [‘Michael‘,‘Jack‘] Python支持L[-1]取倒数第一个元素 >>> L[-2:] [‘Bob‘,‘Jack‘] >>> L[-2:-1] [‘Bob‘] tuple也是一种list,唯一区别是tuple不可变。因此,tuple也可以用切片操作,只是操作的结果仍是tuple >>> (0,1,4,5)[:3]
(0,1,2)
字符串‘xxx‘也可以看成是一种list,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串 >>> ‘ABCDEFG‘[:3] ‘ABC‘ >>> ‘ABCDEFG‘[::2] ‘ACEG‘ 2.2 迭代如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代 >>> d = {‘a‘: 1,‘b‘: 2,‘c‘: 3} >>> for key in d: ... print(key) 迭代value for value in d.values() 同时迭代key和value for k,v in d.items() 由于字符串也是可迭代对象,因此,也可以作用于for循环 >>> for ch in ‘ABC‘: ... print(ch) ... A B C 判断一个对象是可迭代对象,通过collections模块的Iterable类型判断 >>> from collections import Iterable >>> isinstance(‘abc‘,Iterable) # str是否可迭代 True >>> isinstance([1,3],Iterable) # list是否可迭代 True >>> isinstance(123,Iterable) # 整数是否可迭代 False Python内置的enumerate函数可以把一个list变成索引-元素对 >>> for i,value in enumerate([‘A‘,‘B‘,‘C‘]): ... print(i,value) ... 0 A 1 B 2 C 2.3 列表生成式列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式 >>> list(range(1,11))
[1,10]
生成[1x1,2x2,3x3,...,10x10] >>> [x * x for x in range(1,11)] [1,16,25,36,49,64,81,100] for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方 >>> [x * x for x in range(1,11) if x % 2 == 0] [4,100] 还可以使用两层循环,可以生成全排列 >>> [m + n for m in ‘ABC‘ for n in ‘XYZ‘] [‘AX‘,‘AY‘,‘AZ‘,‘BX‘,‘BY‘,‘BZ‘,‘CX‘,‘CY‘,‘CZ‘] 列表生成式也可以使用两个变量来生成list >>> d = {‘x‘: ‘A‘,‘y‘: ‘B‘,‘z‘: ‘C‘ } >>> [k + ‘=‘ + v for k,v in d.items()] [‘y=B‘,‘x=A‘,‘z=C‘] 把一个list中所有的字符串变成小写 >>> L = [‘Hello‘,‘World‘,‘IBM‘,‘Apple‘] >>> [s.lower() for s in L] [‘hello‘,‘world‘,‘ibm‘,‘apple‘] 2.4 生成器如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator >>> L = [x * x for x in range(10)] >>> L [0,81] >>> g = (x * x for x in range(10)) >>> g <generator object <genexpr> at 0x1022ef630> 如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值 >>> next(g) 0 >>> next(g) 1 >>> next(g) 4 定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator def fib(max): n,b = 0,1 while n < max: yield b a,b = b,a + b n = n + 1 return ‘done‘
2.5 迭代器可以直接作用于for循环的数据类型有以下几种: >>> 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 而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。 >>> from collections import Iterator >>> isinstance((x for x in range(10)),Iterator) True >>> isinstance([],Iterator) False >>> isinstance({},Iterator) False >>> isinstance(‘abc‘,Iterator) False (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |