
本文共 8795 字,大约阅读时间需要 29 分钟。
1.函数前导
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。我们已经知道Python提供了许多内建函数,比如print()。但也可以自己创建函数,这被叫做用户自定义函数。
2.函数定义
你可以定义一个由自己想要功能的函数,以下是简单的规则:
- 函数代码块以def关键词开头,后接函数标识符名称和圆括号()。
- 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号起始,并且缩进。
- Return[expression]结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
语法:
def functionname( parameters ): "函数_文档字符串" function_suite
默认情况下,参数值和参数名称是按函数声明中定义的的顺序匹配起来的。
示例如下:
def printme( str ): "打印传入的字符串到标准显示设备上" print str return
3.函数调用
定义一个函数只给了函数一个名称,指定了函数里包含的参数,和代码块结构。
这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从Python提示符执行。
示例如下:
def printme( str ): "打印任何传入的字符串" print str; return; # Now you can call printme functionprintme("我要调用用户自定义函数!");printme("再次调用同一函数");
输出结果:
我要调用用户自定义函数!再次调用同一函数
4.参数传递
在python中,类型属于对象,变量是没有类型的
a=[1,2,3]a="w3cschool"
以上代码中,[1,2,3] 是 List 类型,"w3cschool"是String类型,而变量a是没有类型,她仅仅是一个对象的引用(一个指针),可以是List类型对象,也可以指向 String类型对象。
可更改(mutable)与不可更改(immutable)对象
在python中,strings, tuples, 和numbers是不可更改的对象,而 list,dict 等则是可以修改的对象。
- 不可变类型:变量赋值a=5后再赋值a=10,这里实际是新生成一个int值对象10,再让a指向它,而5被丢弃,不是改变a的值,相当于新生成了a。
- 可变类型:变量赋值la=[1,2,3,4] 后再赋值la[2]=5则是将list la的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。
python 函数的参数传递:
- 不可变类型:类似c++的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
- 可变类型:类似c++的引用传递,如 列表,字典。如fun(la),则是将la真正的传过去,修改后fun外部的la也会受影响
python中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。
python 传不可变对象实例
实例(Python 2.0+)
def ChangeInt( a ): a = 10b = 2ChangeInt(b)print b # 结果是 2
实例中有int对象2,指向它的变量是b,在传递给ChangeInt函数时,按传值的方式复制了变量b,a和b都指向了同一个 Int 对象,在a=10时,则新生成一个int值对象 10,并让a指向它。
按值传递参数和按引用传递参数(传可变对象实例)
所有参数(自变量)在Python里都是按引用传递。如果你在函数里修改了参数,那么在调用这个函数的函数里,原始的参数也被改变了。例如:
# 可写函数说明def changeme( mylist ): "修改传入的列表" mylist.append([1,2,3,4]); print "函数内取值: ", mylist return# 调用changeme函数mylist = [10,20,30];changeme( mylist );print "函数外取值: ", mylist
传入函数的和在末尾添加新内容的对象用的是同一个引用。故输出结果如下:
函数内取值: [10, 20, 30, [1, 2, 3, 4]]函数外取值: [10, 20, 30, [1, 2, 3, 4]]
5.参数
以下是调用函数时可使用的正式参数类型:
- 必备参数
必备参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
调用printme()函数,你必须传入一个参数,不然会出现语法错误,示例如下:
#可写函数说明def printme( str ): "打印任何传入的字符串" print str; return; #调用printme函数printme();
输出结果:
Traceback (most recent call last): File "test.py", line 11, inprintme();TypeError: printme() takes exactly 1 argument (0 given)
- 命名参数
命名参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
使用命名参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
示例如下:
#可写函数说明def printinfo( name, age ): "打印任何传入的字符串" print "Name: ", name; print "Age ", age; return;#调用printinfo函数printinfo( age=50, name="miki" );
输出结果:
Name: mikiAge 50
- 缺省参数
调用函数时,缺省参数的值如果没有传入,则被认为是默认值。
示例如下:
#可写函数说明def printinfo( name, age = 35 ): "打印任何传入的字符串" print "Name: ", name; print "Age ", age; return;#调用printinfo函数printinfo( age=50, name="miki" );printinfo( name="miki" );
输出结果:
Name: mikiAge 50Name: mikiAge 35
- 不定长参数
如果需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述3种参数不同,声明时不会命名。基本语法如下:
def functionname([formal_args,] *var_args_tuple ): "函数_文档字符串" function_suite return [expression]
加了星号(*)的变量名会存放所有未命名的变量参数。选择不多传参数也可。如下实例:
# 可写函数说明def printinfo( arg1, *vartuple ): "打印任何传入的参数" print "输出: " print arg1 for var in vartuple: print var return;# 调用printinfo 函数printinfo( 10 );printinfo( 70, 60, 50 );
以上实例输出结果:
输出:10输出:706050
6.匿名函数
类似Java,python 使用 lambda 来创建匿名函数。
- lambda只是一个表达式,函数体比def简单很多。
- lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
- lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。
- 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
lambda函数的语法只包含一个语句,如下:
lambda [arg1 [,arg2,.....argn]]:expression
示例如下:
#可写函数说明sum = lambda arg1, arg2: arg1 + arg2;#调用sum函数print "Value of total : ", sum( 10, 20 )print "Value of total : ", sum( 20, 20 )
输出结果:
Value of total : 30Value of total : 40
7.return语句
return语句[表达式]退出函数,选择性地向调用方返回一个表达式。不带参数值的return语句返回None。之前的例子都没有示范如何返回数值。
示例如下:
#coding=utf-8#!/usr/bin/python# 可写函数说明def sum( arg1, arg2 ): # 返回2个参数的和." total = arg1 + arg2 print "Inside the function : ", total return total; # 调用sum函数total = sum( 10, 20 );print "Outside the function : ", total
以上实例输出结果:
Inside the function : 30Outside the function : 30
8.变量作用域
一个程序的所有的变量并不是在哪个位置都可以访问的。访问权限决定于这个变量是在哪里赋值的。
变量的作用域决定了在哪一部分程序你可以访问哪个特定的变量名称。两种最基本的变量作用域如下:
- 全局变量
- 局部变量
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。
局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。
实例如下:
total = 0; # This is global variable.# 可写函数说明def sum( arg1, arg2 ): #返回2个参数的和." total = arg1 + arg2; # total在这里是局部变量. print "Inside the function local total : ", total return total;#调用sum函数sum( 10, 20 );print "Outside the function global total : ", total
以上实例输出结果:
Inside the function local total : 30Outside the function global total : 0
9.函数式编程
函数式编程的特点
- 把计算视为函数而非指令
- 纯函数式编程,不需要变量,没有副作用,测试简单
- 支持高阶函数,代码简洁
python支持的函数式编程
- 不是纯函数式编码:允许有变量
- 支持高阶函数:函数也可以作为变量传入
- 支持闭包:有了闭包就能返回函数
- 有限度地支持匿名函数
10.高阶函数
高阶函数:只能接收函数作为参数的函数
- 变量可以是指向函数
- 函数的参数可以接收变量
- 一个函数可以接收另一个函数作为参数
- 能接收函数作为参数的函数就是高阶函数
下面介绍几个常见的高阶函数
- map()函数
map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回。
例如,对于list [1, 2, 3, 4, 5, 6, 7, 8, 9] ,如果希望把list的每个元素都作平方,就可以用map()函数。 只需要传入函数f(x)=x*x,就可以利用map()函数完成这个计算(**注意: python3中map()返回iterators类型,不再是list类型。进行list转换即可 **):
示例如下:
def f(x): return x*xprint map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
输出结果:
[1, 4, 9, 10, 25, 36, 49, 64, 81]
注意:map()函数不改变原有的 list,而是返回一个新的 list
- reduce()函数
reduce()函数也是Python内置的一个高阶函数。reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。
例如,编写一个f函数,接收x和y,返回x和y的和:
def f(x, y): return x + y
调用 reduce(f, [1, 3, 5, 7, 9]) 时,reduce函数将做如下计算:
先计算头两个元素:f(1, 3),结果为4;再把结果和第3个元素计算:f(4, 5),结果为9;再把结果和第4个元素计算:f(9, 7),结果为16;再把结果和第5个元素计算:f(16, 9),结果为25;由于没有更多的元素了,计算结束,返回结果25。
上述计算实际上是对 list 的所有元素求和。虽然Python内置了求和函数sum(),但是,利用reduce()求和也很简单。
reduce()还可以接收第3个可选参数,作为计算的初始值。如果把初始值设为100,计算:
reduce(f, [1, 3, 5, 7, 9], 100)
结果将变为125,因为第一轮计算是:
计算初始值和第一个元素:f(100, 1),结果为101。
示例
Python内置了求和函数sum(),但没有求积的函数,请利用recude()来求积:
输入:[2, 4, 5, 7, 12]
输出:245712的结果1 from functools import reduce2 def prod(x, y):3 return x*y4 5 print(reduce(prod,[2,4,5,7,12]))
注意:在python3.x后的版本中,reduce函数被划归到的functools库,因此使用reduce函数之前必须先引入functools库
- filter()函数
filter()函数是 Python 内置的另一个有用的高阶函数,filter()函数接收一个函数 f 和一个list*,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。
例如,要从一个list [1, 4, 6, 7, 9, 12, 17]中删除偶数,保留奇数,首先,要编写一个判断奇数的函数:
def is_odd(x): return x % 2 == 1
然后,利用filter()过滤掉偶数:
filter(is_odd, [1, 4, 6, 7, 9, 12, 17])
结果:[1, 7, 9, 17]
利用filter(),可以完成很多有用的功能,例如,删除 None 或者空字符串:
def is_not_empty(s): return s and len(s.strip()) > 0filter(is_not_empty, ['test', None, '', 'str', ' ', 'END'])
结果:[‘test’, ‘str’, ‘END’]
注意: s.strip(rm) 删除 s 字符串中开头、结尾处的 rm 序列的字符。
当rm为空时,默认删除空白符(包括’\n’, ‘\r’, ‘\t’, ’ '),如下:
a = ' 123'a.strip()
结果: ‘123’
a='\t\t123\r\n'a.strip()
结果:‘123’
示例
请利用filter()过滤出1~100中平方根是整数的数,即结果应该是:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
代码
import mathdef is_sqr(x): a = math.sqrt(x)%1 if a ==0.0: return True else: return Falsel = filter(is_sqr, range(1,101))print(list(l))
- sort()函数
Python内置的 sorted()函数可对list进行排序:
>>> sorted([36, 5, 12, 9, 21])[5, 9, 12, 21, 36]
但 sorted()也是一个高阶函数,它可以接收一个比较函数来实现自定义排序,比较函数的定义是,传入两个待比较的元素 x, y,如果 x 应该排在 y 的前面,返回 -1,如果 x 应该排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0。
因此,如果我们要实现倒序排序,只需要编写一个reversed_cmp函数:
def reversed_cmp(x, y): if x > y: return -1 if x < y: return 1 return 0
这样,调用 sorted() 并传入 reversed_cmp 就可以实现倒序排序:
>>> sorted([36, 5, 12, 9, 21], reversed_cmp)[36, 21, 12, 9, 5]
sorted()也可以对字符串进行排序,字符串默认按照ASCII大小来比较:
>>> sorted(['bob', 'about', 'Zoo', 'Credit'])['Credit', 'Zoo', 'about', 'bob']
'Zoo’排在’about’之前是因为’Z’的ASCII码比’a’小。
示例
对字符串排序时,有时候忽略大小写排序更符合习惯。请利用sorted()高阶函数,实现忽略大小写排序的算法。
输入:[‘bob’, ‘about’, ‘Zoo’, ‘Credit’]
输出:[‘about’, ‘bob’, ‘Credit’, ‘Zoo’]#-*- coding=utf8 -*- #这段代码在Python2.7可以运行,python3.x之后sorted函数不支持自定义比较函数,在python3.x中sorted函数的定义为#sorted(iterable, /, *, key=None, reverse=False)#可以通过将reverse参数设置为True来实现上面的功能def cmp_ignore_case(s1, s2): if s1.lower()> s2.lower(): return 1 elif s1.lower()< s2.lower(): return -1 else: return 0print sorted(['bob','about','Zoo','Credit'], cmp_ignore_case)
- 偏函数
当一个函数有很多参数时,调用者就需要提供多个参数。如果减少参数个数,就可以简化调用者的负担。
比如,int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换:
>>> int('12345')12345
但int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做 N 进制的转换:
>>> int('12345', base=8)5349>>> int('12345', 16)74565
假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,于是,我们想到,可以定义一个int2()的函数,默认把base=2传进去:
def int2(x, base=2): return int(x, base)
functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2:
>>> import functools>>> int2 = functools.partial(int, base=2)>>> int2('1000000')64>>> int2('1010101')85
所以,functools.partial可以把一个参数多的函数变成一个参数少的新函数,少的参数需要在创建时指定默认值,这样,新函数调用的难度就降低了。
发表评论
最新留言
关于作者
