Python基础编程(六)抽象
6.3 创建函数
一般来说,内建的callable函数可以用来判断函数是否可调用:
>>> import math >>> x = 1 >>> y = math.sqrt >>>callable(x) Falsse >>>callable(y) True使用def语句定义函数:
def hello(name): return 'Hello,' + name + '!'
6.3.1 记录函数
如果想哟啊给函数写文档,让后面使用该函数人能理解的话,可以加入注释(以#开头)。另外一个方式就是直接写上字符串。
如果在函数的开头写下字符串,它就会作为函数的一部分进行存储,这称为文档字符串。def square(x): 'Calculates the square of the number x.' return x*x文档字符串可以按如下方式访问:
>>> square._doc_ 'Calculates the square of the number x.'内建的help函数是非常有用的。在交互式解释其中使用它,就可以得到关于函数,包括它的文档字符串的信息:
>>> help(square) Help on function square in module _main_: square(x) Calculates the square of the number x.
6.4 参数魔法
6.4.2 我能改变参数吗
字符串(以及数字和元组)是不可变的,既无法被修改(也就是说只能用新的值覆盖)。所以它们做参数的时候也就无需多做介绍。但是考虑一下如果将可变的数据结构和列表用作参数的时候会发生什么:
>>> def change(n): n[0] = 'Mr. Gumby' >>> names = ['Mrs. Entry','Mrs. Thing'] >>> change(names) >>> names ['Mr. Gumby','Mrs. Thing']当两个变量同时引用一个列表的时候,它们的却是同时引用一个列表。为了避免出现这种情况,可以复制一个列表的副本。当在序列中做切片的时候,返回的切片总是一个副本。因此,如果你复制了整个列表的切片,将会得到一个副本:
>>> chenge(name[:]) >>> names ['Mrs. Entity','Mrs. Thing']
1. 为什么我想要修改参数
使用函数改变数据结构(比如列表和字典)是将程序抽象化的好方法。
2. 如果我的参数不变呢
在某些语言(比如C++、Pscal和Ada)中,重绑定参数并且是这些改变影响到函数外的变量是很平常的事情。#不是太清楚#但在Python中这是不可能的:函数只能修改参数对象本身。
如果参数不可变呢,比如数字:
>>> def inc(x): trturn x + 1 >>> foo = 10 >>> foo = inc(foo) >>> foo 11如果真的想改变参数,可以将值放置在列表中:
>>> def inc(x): x[0] = x[0] + 1 >>> foo = [10] >>> inc(foo) >>> foo [11]
6.4.3 关键字参数和默认值
目前为止我们所使用的参数都叫做位置参数,因为它们的位置很重要——事实上比他们的名字更加重要。
有些时候(尤其是参数很多的时候),参数的顺序是很难记住的。为了让事情简单些,可以提供参数的名字:
def hello_1(greeting.name): print '%s, %s!' % (greeting,name) def hello_2(name,greeting): print '%s, %s!' % (name,greeting)
>>>hello_1(name='Hello',greeting='word') Hello,word! >>>hello_1(greeting='word',name='Hello') Hello,word!但是参数名和值一定要对应。
关键字参数还可以在函数中给参数提供默认值:
def hello_3(greeting='Hello',name='word'): print '%s, %s!' % (greeting,name)位置和关键字参数还可以联合使用,把位置参数放置在前面就可以了。
6.4.4 收集参数
>>> def print_params(*params): print params >>> print_params('Testing') ('Testing',) >>> print_params(1,2,3) (1,2,3)参数前的星号将所有的值放置在同一个元组中。可以说是将这些值收集起来,然后使用。
>>> def print_params_2(title.*params): print title print params >>> print_params_2('Params:',1,2,3) Params: (1,2,3)星号的意思就是”收集其余的位置参数“。如果不提供任何供收集的元素,params就是个空元组。
另外一个能处理关键字参数的”收集“操作。
>>> def print_params_3(**params): print params >>> print_params_3(x=1,y=2,z=3) {'z':3,'x':1,'y':2}返回的字典而不是元组。
>>> def pirnt_params_4(x,y,z=3,*pospar,**keypar): print x,y,z print pospar print keypar >>> print_params_4(1,2,3,4,5,6,7,foo=1,bar=2) 1 2 3 (5,6,7) {'foo':1,'bar':2} >>> print_params_4(1,2) 1 2 3 () {}
6.4.5 反转过程
函数收集的逆过程是什么样?
不是要收集参数,而是分解它们在“另一端”。使用*运算符就简单了——不过是在调用而不是在定义是使用:
>>> params = (1,2) >>> add(*params) 3可以使用同样的技术来处理字典——使用双星号运算符:
>>> params = {'name':'Sir Robin','Greeting':'Well met'} >>> hello_3(**params) Well met,Sir Robin!
6.5 作用域
命名空间或者说作用域。在执行x=1赋值语句时,名称x引用到值1。这就像字典一样,键引用值。内建的vars函数可以返回这个字典:
>>> x = 1 >>> scope = vars() >>> scope['x'] 1 >>> scope['x'] += 1 2
>>> def foo(): x = 42 >>> x = 1 >>> foo() >>> x 1这里的foo函数改变(重绑定)了变量x,单数在最后的时候,x并没有变。这是因为当调用foo的时候,新的命名空间就被创建了,它作用于foo内的代码块。
重绑定全局变量。如果在还是函数内部将值赋予一个变量,它会自动成为局部变量——除非告知Python将其声明为全局变量。(global)
>>> x = 1 >>> def change_global(): global x x = x + 1 >>> change_global() >>> x 2
6.6 递归
def recursion(): return recursion()