<> = 函数 = 函数是重用的程序段。它们允许你给一块语句一个名称,然后你可以在你的程序的任何地方使用这个名称任意多次地运行这个语句块。这被称为 调用 函数。我们已经使用了许多内建的函数,比如len和range。 函数通过def关键字定义。def关键字后跟一个函数的 标识符 名称,然后跟一对圆括号。圆括号之中可以包括一些变量名,该行以冒号结尾。接下来是一块语句,它们是函数体。下面这个例子将说明这事实上是十分简单的: {{{#!python #!/usr/bin/python def sayHello(): print 'Hello World!' # block belonging to the function sayHello() # call the function }}} 输出 {{{ Hello World! }}} 我们使用上面解释的语法定义了一个称为sayHello的函数。这个函数不使用任何参数,因此在圆括号中没有声明任何变量。参数对于函数而言,只是给函数的输入,以便于我们可以传递不同的值给函数,然后得到相应的结果。 == 函数形参 == 函数取得的参数是你提供给函数的值,这样函数就可以利用这些值 做 一些事情。这些参数就像变量一样,只不过它们的值是在我们调用函数的时候定义的,而非在函数本身内赋值。 参数在函数定义的圆括号对内指定,用逗号分割。当我们调用函数的时候,我们以同样的方式提供值。注意我们使用过的术语——函数中的参数名称为 形参 而你提供给函数调用的值称为 实参 。 {{{#!python #!/usr/bin/python def printMax(a, b): if a > b: print a, 'is maximum' else: print b, 'is maximum' printMax(3, 4) # directly give literal values x = 5 y = 7 printMax(x, y) # give variables as arguments }}} 输出 {{{ 4 is maximum 7 is maximum }}} 这里,我们定义了一个称为printMax的函数,这个函数需要两个形参,叫做a和b。我们使用if..else语句找出两者之中较大的一个数,并且打印较大的那个数。 在第一个printMax使用中,我们直接把数,即实参,提供给函数。在第二个使用中,我们使用变量调用函数。printMax(x, y)使实参x的值赋给形参a,实参y的值赋给形参b。在两次调用中,printMax函数的工作完全相同。 == 局部变量 == 当你在函数定义内声明变量的时候,它们与函数外具有相同名称的其他变量没有任何关系,即变量名称对于函数来说是 局部 的。这称为变量的 作用域 。所有变量的作用域是它们被定义的块,从它们的名称被定义的那点开始。 {{{#!python #!/usr/bin/python def func(x): print 'x is', x x = 2 print 'Changed local x to', x x = 50 func(x) print 'x is still', x }}} 输出 {{{ x is 50 Changed local x to 2 x is still 50 }}} 在函数中,我们第一次使用x的 值 的时候,Python使用函数声明的形参的值。 接下来,我们把值2赋给x。x是函数的局部变量。所以,当我们在函数内改变x的值的时候,在主块中定义的x不受影响。 在最后一个print语句中,我们证明了主块中的x的值确实没有受到影响。 == global语句 == 如果你想要为一个定义在函数外的变量赋值,那么你就得告诉Python这个变量名不是局部的,而是 全局 的。我们使用global语句完成这一功能。没有global语句,是不可能为定义在函数外的变量赋值的。 你可以使用定义在函数外的变量的值(假设在函数内没有同名的变量)。然而,我并不鼓励你这样做,并且你应该尽量避免这样做,因为这使得程序的读者会不清楚这个变量是在哪里定义的。使用global语句可以清楚地表明变量是在外面的块定义的。 {{{#!python #!/usr/bin/python def func(): global x print 'x is', x x = 2 print 'Changed local x to', x x = 50 func() print 'Value of x is', x }}} 输出 {{{ x is 50 Changed global x to 2 Value of x is 2 }}} global语句被用来声明x是全局的——因此,当我们在函数内把值赋给x的时候,这个变化也反映在我们在主块中使用x的值的时候。 你可以使用同一个global语句指定多个全局变量。例如global x, y, z。 == 默认参数值 == 对于一些函数,你可能希望它的一些参数是 可选 的,如果用户不想要为这些参数提供值的话,这些参数就使用默认值。这个功能借助于默认参数值完成。你可以在函数定义的形参名后加上赋值运算符(=)和默认值,从而给形参指定默认参数值。 注意,默认参数值应该是一个参数。更加准确的说,默认参数值应该是不可变的——这会在后面的章节中做详细解释。从现在开始,请记住这一点。 {{{#!python #!/usr/bin/python def say(message, times = 1): print message * times say('Hello') say('World', 5) }}} 输出 {{{ Hello WorldWorldWorldWorldWorld }}} 名为say的函数用来打印一个字符串任意所需的次数。如果我们不提供一个值,那么默认地,字符串将只被打印一遍。我们通过给形参times指定默认参数值1来实现这一功能。 在第一次使用say的时候,我们只提供一个字符串,函数只打印一次字符串。在第二次使用say的时候,我们提供了字符串和参数5,表明我们想要 说 这个字符串消息5遍。 只有在形参表末尾的那些参数可以有默认参数值,即你不能在声明函数形参的时候,先声明有默认值的形参而后声明没有默认值的形参。这是因为赋给形参的值是根据位置而赋值的。例如,def func(a, b=5)是有效的,但是def func(a=5, b)是 无效 的。 == 关键字参数 == 如果你的某个函数有许多参数,而你只想指定其中的一部分,那么你可以通过命名来为这些参数赋值——这被称作 关键参数——我们使用名字(关键字)而不是位置(我们前面所一直使用的方法)来给函数指定实参。 这样做有两个好处:一,由于我们不必担心参数的顺序,使用函数变得更加简单了。二、假设其他参数都有默认值,我们可以只给我们想要的那些参数赋值。 {{{#!python #!/usr/bin/python def func(a, b=5, c=10): print 'a is', a, 'and b is', b, 'and c is', c func(3, 7) func(25, c=24) func(c=50, a=100) }}} 输出 {{{ a is 3 and b is 7 and c is 10 a is 25 and b is 5 and c is 24 a is 100 and b is 5 and c is 50 }}} 名为func的函数有一个没有默认值的参数,和两个有默认值的参数。 在第一次使用函数的时候, func(3, 7),参数a得到值3,参数b得到值7,而参数c使用默认值10。 在第二次使用函数func(25, c=24)的时候,根据实参的位置变量a得到值25。根据命名,即关键参数,参数c得到值24。变量b根据默认值,为5。 在第三次使用func(c=50, a=100)的时候,我们使用关键参数来完全指定参数值。注意,尽管函数定义中,a在c之前定义,我们仍然可以在a之前指定参数c的值。 == 变长参数列表 == 引入一个形如 **name 的参数时,它接收一个 字典 ,该字典包含了所有未出现在形式参数列表中的关键字参数。还可以组合使用一个形如 *name 的形式参数,它接收一个元组,包含了所有没有出现在形式参数列表中的参数值。(*name 必须在 **name 之前出现) 例如,我们这样定义一个函数: {{{#!python def func(a, b=5, c=10, *arguments, **keywords): print 'a is', a, 'and b is', b, 'and c is', c print arguments print keywords func(1.0) func(1.0, c=2, d=4, e=6) func(2, 3, 4, 5, 6, f=7) }}} 在调用的时候,可以把一个列表拆开来传给各个参数,还可以把一个字典分开为各个关键字参数。比如 {{{ s = [1,2,3,4,5,6] func(*s) d = {'a':1, 'b':2, 'c':2, 'd':3} func(**d) }}} == return语句 == return语句用来从一个函数 返回 即跳出函数。我们也可选从函数 返回一个值 。 {{{#!python #!/usr/bin/python def maximum(x, y): if x > y: return x else: return y print maximum(2, 3) }}} 输出 {{{ 3 }}} maximum函数返回参数中的最大值,在这里是提供给函数的数。它使用简单的if..else语句来找出较大的值,然后 返回 那个值。 注意,没有返回值的return语句等价于return None。None是Python中表示没有任何东西的特殊类型。例如,如果一个变量的值为None,可以表示它没有值。 除非你提供你自己的return语句,每个函数都在结尾暗含有return None语句。通过运行print someFunction(),你可以明白这一点,函数someFunction没有使用return语句,如同: {{{#!python def someFunction(): pass }}} pass语句在Python中表示一个空的语句块。 == 文档字符串 == Python有一个很奇妙的特性,称为 文档字符串 ,它通常被简称为 docstrings 。文档字符串是一个重要的工具,由于它帮助你的程序文档更加简单易懂,你应该尽量使用它。你甚至可以在程序运行的时候,从函数获得文档字符串! {{{#!python #!/usr/bin/python def printMax(x, y): '''Prints the maximum of two numbers. The two values must be integers.''' x = int(x) # convert to integers, if possible y = int(y) if x > y: print x, 'is maximum' else: print y, 'is maximum' printMax(3, 5) print printMax.__doc__ }}} 输出 {{{ 5 is maximum Prints the maximum of two numbers. The two values must be integers. }}} 在函数的第一个逻辑行的字符串是这个函数的 文档字符串 。注意,文档字符串也适用于模块和类,我们会在后面学习它们。 文档字符串的惯例是一个多行字符串,它的首行以大写字母开始,句号结尾。第二行是空行,从第三行开始是详细的描述。 强烈建议 你在你的函数中使用文档字符串时遵循这个惯例。 你可以使用{{{__doc__}}}(注意双下划线)调用printMax函数的文档字符串属性(属于函数的名称)。请记住Python把 每一样东西 都作为对象,包括这个函数。 如果你已经在Python中使用过help(),那么你已经看到过文档字符串的使用了!help()所做的只是抓取函数的{{{__doc__}}}属性,然后整洁地展示给你。你可以对上面这个函数尝试一下——只是在你的程序中包括help(printMax)。记住按q退出help。 自动化工具也可以以同样的方式从你的程序中提取文档。因此,我 强烈建议 你对你所写的任何正式函数编写文档字符串。随你的Python发行版附带的pydoc命令,与help()类似地使用文档字符串。 == lambda == lambda语句被用来创建新的函数对象,并且在运行时返回它们。 {{{#!python #!/usr/bin/python def make_repeater(n): return lambda s: s*n twice = make_repeater(2) print twice('word') print twice(5) }}} 输出 {{{ wordword 10 }}} 这里,我们使用了make_repeater函数在运行时创建新的函数对象,并且返回它。lambda语句用来创建函数对象。本质上,lambda需要一个参数,后面仅跟单个表达式作为函数体,而表达式的值被这个新建的函数返回。注意,即便是print语句也不能用在lambda形式中,只能使用表达式。 == 函数式编程 == 对于链表来讲,有三个内置函数非常有用:filter(), map(), 和 reduce()。 "filter(function, sequence)"返回一个序列(sequence),包括了给定序列中所有调用function(item)后返回值为true的元素。(如果可能的话,会返回相同的类型)。例如,以下程序可以计算部分素数: {{{ >>> def f(x): return x % 2 != 0 and x % 3 != 0 ... >>> filter(f, range(2, 25)) [5, 7, 11, 13, 17, 19, 23] }}} "map(function, sequence)" 为每一个元素依次调用function(item)并将返回值组成一个链表返回。例如,以下程序计算立方: {{{ >>> cube = lambda x: x*x*x ... >>> map(cube, range(1, 11)) [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000] }}} 可以传入多个序列,函数也必须要有对应数量的参数,执行时会依次用各序列上对应的元素来调用函数(如果某些序列比其它的短,就用None来代替)。如果把None做为一个函数传入,则直接返回参数做为替代。例如: {{{ >>> seq = range(8) >>> add = lambda x, y: x+y ... >>> map(add, seq, seq) [0, 2, 4, 6, 8, 10, 12, 14] }}} "reduce(func, sequence)" 返回一个单值,它是这样构造的:首先以序列的前两个元素调用函数,再以返回值和第三个参数调用,依次执行下去。例如,以下程序计算1到10的整数之和: {{{ >>> add = lambda x, y: x+y ... >>> reduce(add, range(1, 11)) 55 }}} 如果序列中只有一个元素,就返回它,如果序列是空的,就抛出一个异常。 可以传入第三个参数做为初始值。如果序列是空的,就返回初始值,否则函数会先接收初始值和序列的第一个元素,然后是返回值和下一个元素,依此类推。例如: {{{ >>> def sum(seq): ... return reduce(lambda x,y:x+y, seq, 0) ... >>> sum(range(1, 11)) 55 >>> sum([]) 0 }}} == 内置函数 == eval语句用来计算存储在字符串中的有效Python表达式。下面是一个简单的例子。 {{{ >>> eval('2*3') 6 }}} repr函数用来取得对象的规范字符串表示。反引号(也称转换符)可以完成相同的功能。注意,在大多数时候有eval(repr(object)) == object。 {{{ >>> i = [] >>> i.append('item') >>> `i` "['item']" >>> repr(i) "['item']" }}} 基本上,repr函数和反引号用来获取对象的可打印的表示形式。你可以通过定义类的{{{__repr__}}}方法来控制你的对象在被repr函数调用的时候返回的内容。 str()返回对象的字符串显示 {{{ >>> s = 'item' >>> repr(s) "'item'" >>> str(s) 'item' }}} len() 求长度 {{{ >>> s = 'item' >>> len(s) 4 }}} help() 看帮助 {{{ import sys help(sys) }}} dir() 看模块或者对象的成员清单。比如用 {{{ dir(__builtins__) }}} 可以看到所有的内置函数的列表。 range()函数用于产生一个列表 {{{ >>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> range(1, 10) [1, 2, 3, 4, 5, 6, 7, 8, 9] >>> range(10, 1, -1) [10, 9, 8, 7, 6, 5, 4, 3, 2] }}} abs()求绝对值 {{{ >>> abs(-1) 1 >>> abs(1+1j) 1.4142135623730951 }}} callable()判断一个对象是否可以作为函数被调用 {{{ >>> callable(len) True >>> callable(9) False }}} chr()返回给定ascii码的字符 {{{ >>> chr(65) 'A' }}} unichr()返回指定unicode编码值的unicode字符 {{{ >>> unichr(65) u'A' }}} ord()返回给定字符的ascii码 {{{ >>> ord('A') 65 >>> ord(u'A') 65 }}} raw_input()读取一行字符串 {{{ >>> raw_input("input a string:") input a string:hello 'hello' }}} input() 输入一个字符串,并对字符串中的表达式求值。等价于eval(raw_input()) {{{ >>> input("input a number:") input a number:10 10 }}} max求最大值 {{{ >>> max(1, 2) 2 >>> max(1, 3, 2) 3 >>> s = [1,2,3,4,5,4,3] >>> max(s) 5 }}} min求最小值,用法和max类似 sum求和 {{{ >>> s = range(10) >>> sum(s) 45 >>> sum(s, 20) 65 }}} type()对象的类型 {{{ >>> type(10) >>> type(3.14159) >>> type('hello world') >>> type(1+1j) >>> type(type) >>> type(len) }}} reversed()倒过来的序列 {{{ >>> s = range(10) >>> reversed(s) >>> [i for i in reversed(s)] [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] >>> for i in reversed(s): ... print i*i, ... 81 64 49 36 25 16 9 4 1 0 }}} sorted()排序的序列 {{{ >>> import random >>> s = [random.randint(1,10) for i in range(10)] >>> print s [10, 5, 7, 4, 6, 7, 10, 8, 7, 3] >>> sorted(s) [3, 4, 5, 6, 7, 7, 7, 8, 10, 10] }}} = end =