11.1.2 返回值与函数类型 python
过程可理解为函数,返回none web
下面代码可简单理解函数返回值的概念: express
>>> defhello(): print "hello world!" >>> res =hello() hello world! >>> printres None >>>type(res) <type'NoneType'> >>> res =hello >>> res() hello world!
另外,与其余大多数的语言同样,python 里的函数能够返回一个值或者对象。只是在返回一个容器对象的时候有点不一样,看起来像是能返回多个对象。比如说,你不能拿着大量零散的商品离开百货店,可是你能够将它们放在一个购物袋里,而后带着这个袋子从商店走出去,合理合法。 编程
>>> def foo(): return["xyz",1000000,-98.6] >>> def bar(): return"abc",[42,"python"], "guido"
foo()函数返回一个列表,bar()函数返回一个元组。因为元组语法上不须要必定带上圆括号,因此让人真的觉得能够返回多个对象。若是咱们要恰当地给这个元组加上括号, bar()的定义看起来会是这样: 数组
>>> def bar(): return("abc",[42,"python"], "guido")
固然,加上括号老是好的。咱们能够这样接收返回值: 闭包
>>> aTuple = bar() >>> x, y, z = bar() >>> (a, b, c) = bar() >>> aTuple ('abc', [42, 'python'], 'guido') >>> x 'abc' >>> x, y, z ('abc', [42, 'python'], 'guido') >>> (a, b, c) ('abc', [42, 'python'], 'guido')
11.2 调用函数 app
11.2.2 关键字参数 框架
关键字参数的概念仅仅针对函数的调用。这种理念是让调用者经过函数调用中的参数名字来区分参数。这样规范容许参数缺失或者不按顺序,由于解释器能经过给出的关键字来匹配参数的值。 dom
例子以下: 函数式编程
>>> def foo(name = "", age = 0): print "name:%s andage:%d" % (name, age) >>> foo(name="fzyz.abc",age=23) name:fzyz.abc and age:23 >>> foo(age=23, name="fzyz.abc") name:fzyz.abc and age:23 >>> foo(age=23) name: and age:23
11.2.4 参数组
固然,你能够向函数中传递没有显式定义的参数,用元祖或字典便可。标准格式以下:
func(positional_args,keyword_args,*tuple_grp_nonkw_args, **dict_grp_kw_args)
咱们来简单看个例子:
from operator import add, sub from random import randint, choice ops = {"+":add, "-":sub} MAXTRIES = 2 def doprob(): op = choice("+-") nums = [randint(1,10) for i inrange(2)] nums.sort(reverse = True) ans = ops[op](*nums) pr = "%d %s %d =" %(nums[0], op, nums[1]) oops = 0 while True: try: if int(raw_input(pr)) ==ans: print"correct" break if oops == MAXTRIES: print"answer\n%s%d" % (pr, ans) else: print"incorrect... try again" oops += 1 except (KeyboardInterrupt,EOFError, ValueError): print "invalid input...try again" def main(): while True: doprob() try: opt =raw_input("again?[y]").lower() if opt and opt[0] == "n": break except (KeyboardInterrupt,EOFError): break if __name__ == "__main__": main()
程序输入输出:
>>> 7 - 1 =6 correct again?[y]y 9 - 5 =4 correct again?[y]n这个程序挺好玩的。
11.3 建立函数
函数是用def 语句来建立的,语法以下:
def function_name(arguments):
"function_documentation_string"
function_body_suite
标题行由def 关键字,函数的名字,以及参数的集合(若是有的话)组成。def 子句的剩余部分包括了一个虽然可选可是强烈推荐的文档字串,和必需的函数体。
Python中并无函数声明和定义的区分,由于一般将它们视为一体。
11.3.5 内部/内嵌函数
在函数体内建立另一个函数(对象)是彻底合法的。这种函数叫作内部/内嵌函数。
>>> def foo(): def bar(): print "bar()called" print "foo() called" bar() >>> foo() foo() called bar() called
>>> class foo(object): def bar(self): print "bar()called" >>> foo().bar() bar() called
11.3.6 *函数(与方法)装饰器
装饰器背后的主要动机源自python 面向对象编程。装饰器是在函数调用之上的修饰。这些修饰仅是当声明一个函数或者方法的时候,才会应用的额外调用。
装饰器的语法以@开头,接着是装饰器函数的名字和可选的参数。紧跟着装饰器声明的是被修饰的函数,和装饰函数的可选参数。装饰器看起来会是这样:
@decorator(dec_opt_args)
def func2Bdecorated(func_opt_args):
:
为何会产生装饰器呢?咱们来看看静态方法的实现:
class MyClass(object):
def staticFoo():
:
staticFoo = staticmethod(staticFoo)
在这个类的声明中,咱们定义了叫staticFoo()的方法。如今由于打算让它成为静态方法,咱们省去它的self 参数,self 参数在标准的类方法中是必需的。接着用staticmethod()内建函数来将这个函数“转化“为静态方法,可是在defstaticFoo()后跟着staticFoo = staticmethod (sta- ticFoo)显得有多么的臃肿。使用装饰器,你如今能够用以下代码替换掉上面的:
class MyClass(object):
@staticmethod
def staticFoo():
此外,装饰器能够如函数调用同样“堆叠“起来,这里有一个更加广泛的例子,使用了多个装饰器:
@deco2
@deco1
def func(arg1, arg2, ...): pass
这和建立一个组合函数是等价的。
def func(arg1, arg2, ...): pass
func = deco2(deco1(func))
咱们来举个简单的装饰器例子:
class MyClass(object): @staticmethod def the_static_method(x): print x MyClass.the_static_method(2)我本来想写个复杂的装饰器程序的,结果写了半天没写出来,我去,我想把装饰器弄到类里面来个函数嵌套函数的调用,
有参数和无参数的装饰器
没有参数的状况:
def foo(): pass
....很是的直接
foo = deco(foo)
跟着是无参函数(如上面所见)组成。然而,带参数的装饰器decomaker()
@decomaker(deco_args)
def foo(): pass
. . .
须要本身返回以函数做为参数的装饰器。换句话说,decomaker()用deco_args 作了些事并返回
函数对象,而该函数对象正是以foo 做为其参数的装饰器。简单的说来:
foo = decomaker(deco_args)(foo)
本身写不出例子,那么咱们来看看书本上的例子吧(真的很想经过装饰器来完成函数调用函数的举例,不过老是出错,我去。。。)
这个装饰器(以及闭包)示范代表装饰器仅仅是用来“装饰“(或者修饰)函数的包装,返回一个修改后的函数对象,将其从新赋值原来的标识符,并永久失去对原始函数对象的访问。
from time import ctime, sleep def tsfunc(func): def wrappedFunc(): print "[%s] %s()called" % (ctime(), func.__name__) return func return wrappedFunc @tsfunc def foo(): pass foo() for i in range(2): sleep(1) foo()
>>> [Fri Jun 14 20:16:00 2013] foo() called [Fri Jun 14 20:16:01 2013] foo() called [Fri Jun 14 20:16:02 2013] foo() called
11.4 传递函数
一个将函数做为参数传递,并在函数体内调用这些函数,更加实际的例子。这个脚本用传入的转换函数简单将一个序列的数转化为相同的类型。特别地,test()函数传入一个内建函数int(),long(), 或者float()来执行转换。
def convert(func, seq): return [func(eachNum) foreachNum in seq] myseq = (123, 45.67, -6.2e8, 9999999999L) print convert(int, myseq) print convert(long, myseq) print convert(float, myseq)
>>> [123, 45, -620000000, 9999999999L] [123L, 45L, -620000000L, 9999999999L] [123.0, 45.67, -620000000.0, 9999999999.0]
from urllib import urlretrieve def firstNonBlank(lines): for eachLine in lines: if not eachLine.strip(): continue else: return eachLine def firstLast(webpage): f = open(webpage) lines = f.readlines() f.close() print firstNonBlank(lines), lines.reverse() print firstNonBlank(lines) def download(url="http://www.baidu.com", process = firstLast): try: retval = urlretrieve(url)[0] except IOError: retval = None if retval: process(retval) if __name__ == "__main__": download()
程序就是把百度的首页用HTML的格式输出。
看得有点头晕脑胀的,不过继续看啦。公司竟然断网了,瞬间无语。。。。
本来休息的时候还能够写邮件的,结果一切白谈。。。。
11.6 可变长度的参数
11.6.1 非关键字可变长参数(元祖)
当函数被调用的时候,全部的形参(必须的和默认的)都将值赋给了在函数声明中相对应的局部变量。剩下的非关键字参数按顺序插入到一个元组中便于访问。
def fun(value1, value2 = "hello", *args): print value1, print value2, for item in args: print item, fun("123","world","1","2","3")程序输出:
>>> 123 world 1 2 3可是默认参数貌似没使用成功,先继续往下看,看默认参数如何和元祖结合使用的。
往下看的时候才知道,若是要用到默认参数的话,必须传递的是字典而不是元祖。请看下面的例子:
def fun(value1, value2 = "hello", **args): print value1 print value2 for item in args.keys(): print "key is: %s andvalue is:%s" % (item, str(args[item])) fun("123",value2 = "world", a = 1,b = 2, c = 3)
>>> 123 world key is: a and value is:1 key is: c and value is:3 key is: b and value is:2
fun("123",value2 = "world", "a" =1,"b" = 2, "c" = 3)
想一想就知道了,”a” = 1自己就是一个错误的表达式。
关键字和非关键字可变长参数都有可能用在同一个函数中,只要关键字字典是最后一个参数而且非关键字元组先于它以前出现。
我去,这好复杂,复杂的表达式能少用就尽可能少用。
11.6.3 调用带有可变长参数对象函数
函数式编程举例
def testit(func, *nkwargs, **kwargs): try: retval = func(*nkwargs,**kwargs) result = (True, retval) except Exception, diag: result = (False, str(diag)) return result def test(): funcs = (int, long, float) vals = (1234, 12.34,"1234", "12.34") for eachFunc in funcs: print "-" * 20 for eachVal in vals: retval =testit(eachFunc, eachVal) if retval[0]: print"%s(%s)=" % (eachFunc.__name__,eachVal), retval[1] else: print "%s(%s) =failed:" % (eachFunc.__name__, eachVal), retval[1] if __name__ == "__main__": test()程序输出:
>>> -------------------- int(1234)= 1234 int(12.34)= 12 int(1234)= 1234 int(12.34) = failed: invalid literal for int() with base 10: '12.34' -------------------- long(1234)= 1234 long(12.34)= 12 long(1234)= 1234 long(12.34) = failed: invalid literal for long() with base 10: '12.34' -------------------- float(1234)= 1234.0 float(12.34)= 12.34 float(1234)= 1234.0 float(12.34)= 12.34
11.7 函数式编程
来进入传说中的函数式编程,函数式编程是LISP的核心知识,其实在python中并不过重要,由于python能够用一些技巧来达到函数式编程的效果,好比列表推导式。
11.7.1 匿名函数与lambda
python 容许用lambda 关键字创造匿名函数。匿名是由于不须要以标准的方式来声明,好比说,使用def 语句。(除非赋值给一个局部变量,这样的对象也不会在任何的名字空间内建立名字.)然而,做为函数,它们也能有参数。一个完整的lambda“语句”表明了一个表达式,这个表达式的定义体必须和声明放在同一行。咱们如今来演示下匿名函数的语法:
lambda [arg1[, arg2,... argN]]: expression
参数是可选的,若是使用的参数话,参数一般也是表达式的一部分。
>>> true = lambda : True >>> true <function <lambda> at 0x020C41F0> >>> true() True
>>> (lambda x, y = 2: x + y)(2,3) 5
11.7.2 内建函数apply(), filter(), map(), reduce()
apply(func[, nkw][,kw])
用可选的参数来调用func,nkw 为非关键字参数,kw 关键字参数;返回值是函数调用的返回值。
filter(func, seq)
调用一个布尔函数func来迭代遍历每一个seq 中的元素; 返回一个使func 返回值为ture 的元素的序列。
map(func,seq1[,seq2...])
将函数func 做用于给定序列(s)的每一个元素,并用一个列表来提供返回值;若是func 为None, func 表现为一个身份函数,返回一个含有每一个序列中元素集合的n 个元组的列表。
reduce(func, seq[,init])
将二元函数做用于seq 序列的元素,每次携带一对(先前的结果以及下一个序列元素),连续的将现有的结果和下次给值做用在得到的随后的结果上,最后减小咱们的序列为一个单一的返回值;若是初始值init 给定,第一个比较会是init 和第一个序列元素而不是序列的头两个元素。
Filter的使用:
def func(num): return num > 5 seq = [1,2,3,4,5,6,7,8,9,10] print filter(func, seq)程序输出:
>>> [6, 7, 8, 9, 10]
[item for item in seq if item> 5]
>>> map(lambda x,y:x + y, [1,3,5],[2,4,6]) [3, 7, 11] >>> map(lambda x,y:(x+y, x-y), [1,3,5],[2,4,6]) [(3, -1), (7, -1), (11, -1)] >>> map(None,[1,3,5],[2,4,6]) [(1, 2), (3, 4), (5, 6)]这貌似用列表推导式没法办到,在多余两个参数迭代的状况下。
Reduce的使用:
reduce(func, [1, 2,3]) = func(func(1, 2), 3)
因此,能够用reduce垂手可得的进行列表的累加和计算:
>>> reduce(lambda x,y:x + y, range(5)) 10
刚才看了一下,刚开始以为神奇,可是忽然想起,这不是LISP里面lambda最简单的应用吗?我一样能够用lambda来完成书上的例子:
>>> fun1 = lambda x:x + 1 >>> fun1(4) 5 >>> fun1 = lambda x:int(x, base=2) >>>fun1("10010") 18
偏函数应用GUI
from functools import partial import Tkinter root = Tkinter.Tk() MyButton =partial(Tkinter.Button, root, fg="white",bg="blue") b1 =MyButton(text="button 1") b2 =MyButton(text="button 2") qb = MyButton(text="quit",bg="red",command=root.quit) b1.pack() b2.pack() qb.pack(fill=Tkinter.X,expand=True) root.title("PFAs!") root.mainloop()
其实这里偏函数的做用就是将一个函数封装起来,看成参数传递罢了。
11.8 变量做用域
11.8.1 全局变量与局部变量
“声明适用的程序的范围被称为了声明的做用域。在一个过程当中,若是名字在过程的声明以内,它的出现即为过程的局部变量;不然的话,出现即为非局部的“
全局变量的一个特征是除非被删除掉,不然它们的存活到脚本运行结束,且对于全部的函数,他们的值都是能够被访问的,然而局部变量,就像它们存放的栈,暂时地存在,仅仅只依赖于定义它们的函数现阶段是否处于活动。当一个函数调用出现时,其局部变量就进入声明它们的做用域。在那一刻,一个新的局部变量名为那个对象建立了,一旦函数完成,框架被释放,变量将会离开做用域。
当咱们须要在函数内用到全局变量的时候,能够用关键字global。
11.8.4 闭包
根本就不知道闭包是什么东东,我去,看例子最重要,从例子中进行理解。
def counter(start_at = 0): count = [start_at] def incr(): count[0] += 1 return count[0] return incr
>>> count =counter(5) >>> count() 6 >>> count() 7 >>> count2 =counter(100) >>> count2() 101 >>> count() 8
咱们来作作练习吧:
11-3 函数。在这个练习中,咱们将实现max()和min()内建函数。
(a) 写分别带两个元素返回一个较大和较小元素,简单的max2()核min2()函数。他们应该能够用任意的python 对象运做。举例来讲,max2(4,8)和min2(4,8)会各自每次返回8 和4。
(b) 建立使用了在a 部分中的解来重构max()和min()的新函数my_max()和my_min().这些函数分别返回非空队列中一个最大和最小值。它们也能带一个参数集合做为输入。用数字和字符串来测试你的解。
a)
def max2(num1, num2): return num1 if num1 > num2 else num2 def min2(num1, num2): return num1 if num1 < num2 else num2 print max2(4,8) print min2(4,8)程序输出:
>>> 8 4b)
def max2(num1, num2): return num1 if num1 > num2 else num2 def min2(num1, num2): return num1 if num1 < num2 else num2 def my_max(*args): return reduce(max2, args) def my_min(*args): return reduce(min2, args) print my_max(1,2,3,4,5,6,7,8) print my_min(1,2,3,4,5,6,7,8)程序输出:
>>> 8 1
"""将小时:分钟形式直接表示为分钟格式""" def TranHourToMinute(strTime): num = [] num = strTime.split(":") return int(num[0]) * 60 + int(num[1]) def TranMinuteToHour(strTime): hour,minute = divmod(strTime, 60) return str(hour)+":"+str(minute) if __name__ == "__main__": while True: strTime = raw_input("please enter the time,like 12:12(q to quit):") if strTime.lower() == "q": break print "the time is:%d minutes" % (TranHourToMinute(strTime)) print "the same time is: %s" % (TranMinuteToHour(TranHourToMinute(strTime)))程序输入输出:
>>> please enter the time,like 12:12(q to quit):12:12 the time is:732 minutes the same time is: 12:12 please enter the time,like 12:12(q to quit):q
先放着
11–7. 用map() 进行函数式编程。给定一对同一大小的列表, 如[1 , 2 , 3] 和['abc','def','ghi',....],将两个标归并为一个由每一个列表元素组成的元组的单一的表,以使咱们的结果看起来像这样:{[(1, 'abc'), (2, 'def'), (3, 'ghi'), ...}.(虽然这问题在本质上和第六章的一个问题类似,那时两个解没有直接的联系)而后建立用zip 内建函数建立另外一个解。
>>> map(lambda x, y:(x, y),[1,2,3],["abc","def","ghi"]) [(1, 'abc'), (2, 'def'), (3, 'ghi')] >>> zip([1,2,3],["abc","def","ghi"]) [(1, 'abc'), (2, 'def'), (3, 'ghi')]
def average(*args): return reduce(lambda x, y: x + y, args) / len(args) print average(1,2,3,4,5)程序输出:
>>> 3
11–11.用map()进行函数式编程。写一个使用文件名以及经过除去每行中全部排头和最尾的空白来“清洁“文件。在原始文件中读取而后写入一个新的文件,建立一个新的或者覆盖掉已存在的。给你的用户一个选择来决定执行哪个。将你的解转换成使用列表解析。
这里直接用strip方法最简单,若是非要用map来进行过滤的话,须要本身编写相似strip的一个函数。
def strip(strTemp): return strTemp.strip() while True: fileName = raw_input("please enter the fileName(q to quit):") if fileName.lower() == "q": break choice = raw_input("n to new file, or c to cover file:") if choice.lower() == "n": newFileName = raw_input("please enter the new file name:") with open(newFileName,"w") as fobj: with open(fileName) as fobjold: lines = fobjold.readlines() for line in map(strip, lines): fobj.write(repr(line)) fobj.write("\n") else: with open(fileName) as fobjold: lines = fobjold.readlines() with open(fileName,"w") as fobjold: for line in map(strip, lines): fobjold.write(repr(line)) fobjold.write("\n")看了一下文件,结果正确。
11–12. 传递函数。给在这章中描述的testit()函数写一个姊妹函数。timeit()会带一个函数对象(和参数一块儿)以及计算出用了多少时间来执行这个函数,而不是测试执行时的错误。返回下面的状态:函数返回值,消耗的时间。你能够用time.clock()或者time.time(),不管哪个给你提供了较高的精度。(通常的共识是在POSIX 上用time.time(),在win32 系统上用time.clock())注意:timeit()函数与timeit 模块不相关(在python2.3 中引入)
import time def timeit(fun, *args): time1 = time.clock() for i in range(10000000): fun(*args) time2 = time.clock() return time2 - time1 def fun(*args): return reduce(lambda x, y:x + y, args) if __name__ == "__main__": usingTime = timeit(fun, 1,2,3,4,5,6,7,8,9,10) print "using time is: %d" % usingTime程序输出:
>>> using time is: 19
import time def mult(x, y): return x * y def fac1(n): return reduce(mult, range(1,n)) def fac2(n): return reduce(lambda x, y: x * y, range(1,n)) def timeit(fun, *args): time1 = time.clock() for i in range(1000000): fun(*args) time2 = time.clock() return time2 - time1 print timeit(fac1, 10) print timeit(fac2, 10)程序输出:
>>> 2.41728863642 2.46803054498
def fib(num): a,b = 1,1 while num - 1: a,b = b,a + b num -= 1 return a def new_fib(num, a = 1, b = 1): if num - 1: a,b = b,a+b return new_fib(num - 1, a, b) else: return a print new_fib(8) print fib(8)不过这里递归用的好丑,可是也不知道该怎么弄好就是了。
11–15.递归。从写练习6-5 的解,用递归向后打印一个字符串。用递归向前以及向后打印一个字符串。
def printLeft(strTemp): if strTemp: print strTemp[0], return printLeft(strTemp[1:]) def printRight(strTemp): if strTemp: print strTemp[-1], return printRight(strTemp[:-1]) printLeft("hello world!") print printRight("hello world!")程序输出:
>>> h e l l o w o r l d ! ! d l r o w o l l e h
我的感受,偏函数就是lambda罢了。
而后迭代器和生成器的区别就是一个运行时候很顺利,一个运行时候会一卡一卡的。
PS:异常那章先放在,看得烦躁。