标签:
1.创建函数
函数是可以调用的(可能带有参数,也就是放在圆括号中的值),它执行某种行为并且返回一个值。一般来说,内建的callable函数可以用来判断函数是否可调用:
>>> import math
>>> x = 1
>>> y = math.sqrt
>>> callable(x)
False
>>> callable(y)
True
函数定义
使用def(或“函数定义”)语句即可,后面带圆括号,以冒号结尾。例:
>>> def hello(name) :
... return ‘hello, ‘ + name + "!"
...
>>> print hello(‘world‘)
hello, world!
>>> print hello(‘Alice‘)
hello, Alice!
文档化函数
如果在函数的开头写下字符串,它就会作为函数的一部分进行存储,这称为文档字符串。例:
>>> def square(x) :
... ‘calculates the square of the number x.‘
... return x * x
文档字符串可以按如下方式访问:
>>> square.func_doc
‘calculates the square of the number x.‘
并非正真函数的函数
Python有些函数没有return语句,或者虽有return语句但return后面没有跟任何,这些函数都不会返回值。例:
>>> def test():
... print ‘This is printed !‘
... return
... print ‘This is not !‘
...
>>> x = test()
This is printed !
>>> x
>>> print x
None
注:return语句只起到结束函数的作用。用print语句打印x的值是None。所有函数都会有返回值,当不需要他们返回值的时候,他们就返回None。
2.参数魔法
形参:写在def语句中函数名后面的变量通常叫做函数的形参。
实参:调用函数的时候提供的值叫做实参,或者称为参数。
为什么要修改参数
使用函数改变数据结构(例如列表或者字典)是一种将程序抽象化的好方法。
例:假设要编写一个存储名字并且能根据名字、中间名、或姓查找联系人的程序,可以使用下面的数据结构:
>>> storage ={}
>>> storage[‘first‘] = {}
>>> storage[‘middle‘] ={}
>>> storage[‘last‘] = {}
如果要把我的名字加入到这个数据结构中,可以像下面这样做:
>>> me = {‘Nagnus Lie Hetland‘}
>>> storage[‘first‘][‘Nagnus‘] = me
>>> storage[‘middle‘][‘Lie‘] = me
>>> storage[‘last‘][‘Hetland‘] = me
现在如果想得到素有注册的中间名为Lie的人,可以像下面这么做:
>>> storage[‘middle‘][‘Lie‘]
set([‘Nagnus Lie Hetland‘])
如果要加入其它名字到列表中,会很麻烦,这时函数就可以提高效率了。抽象的要点就是隐藏更新时繁琐的细节,上面初始化数据结构的例子可以通过函数实现,如下:
>>> def init(data) :
... data[‘first‘] = {}
... data[‘middle‘] = {}
... data[‘last‘] = {}
再写个获取名字的函数,如下:
>>> def lookup(data, lable, name) :
... return data[lable].get(name)
...
>>> lookup(storage, ‘middle‘, ‘Lie‘)
set([‘Nagnus Lie Hetland‘])
最后写存储名字的函数,如下:
>>> def store(data, full_name) :
... names = full_name.split()
... if(len(names)) == 2 : names.insert(1, ‘‘)
... lables = (‘first‘, ‘middle‘, ‘last‘)
... for lable, name in zip(lables, names):
... people = lookup(data, lable, name)
... if people :
... people.append(full_name)
... else :
... data[lable][name] = [full_name]
...
运行结果如下所示:
>>> MyNames = {}
>>> init(MyNames)
>>> store(MyNames, ‘Magus Lie Hetland‘)
>>> lookup(MyNames, ‘middle‘, ‘Lie‘)
[‘Magus Lie Hetland‘]
>>> store(MyNames, ‘Robin Hood‘)
>>> store(MyNames, ‘Robin Locksley‘)
>>> lookup(MyNames, ‘first‘, ‘Robin‘)
[‘Robin Hood‘, ‘Robin Locksley‘]
>>> store(MyNames, ‘Mr. Gumby‘)
>>> lookup(MyNames, ‘middle‘, ‘‘)
[‘Robin Hood‘, ‘Robin Locksley‘, ‘Mr. Gumby‘]
>>> MyNames
{‘middle‘: {‘‘: [‘Robin Hood‘, ‘Robin Locksley‘, ‘Mr. Gumby‘], ‘Lie‘: [‘Magus Lie Hetland‘]}, ‘last‘: {‘Gumby‘: [‘Mr. Gumby‘], ‘Locksley‘: [‘Robin Locksley‘], ‘Hood‘: [‘Robin Hood‘], ‘Hetland‘: [‘Magus Lie Hetland‘]}, ‘first‘: {‘Magus‘: [‘Magus Lie Hetland‘], ‘Mr.‘: [‘Mr. Gumby‘], ‘Robin‘: [‘Robin Hood‘, ‘Robin Locksley‘]}}
关键字参数和默认值
之前的例子中使用的参数都是位置参数,因为他们的位置很重要,事实上比他们的名字更加重要。我们现在要引入的这个功能可以回避位置问题。考虑下面两个函数:
>>> def hello(greeting, name):
... print ‘%s, %s !‘ %(greeting, name)
...
>>> def hello1(name, greeting):
... print ‘%s, %s !‘ %(name, greeting)
...
>>> hello(‘Hello‘, ‘world‘)
Hello, world !
>>> hello1(‘Hello‘, ‘world‘)
Hello, world !
以上两个代码实现的功能是完全一样的,只是参数顺序反过来了。有写时候(尤其是参数很多的时候),参数的顺序是很难记住的。为了让事情简单些,可以提供参数的名字。如下所示:
>>> hello(greeting = ‘Hello‘, name = ‘world‘)
Hello, world !
>>> hello(name = ‘world‘, greeting = ‘Hello‘)
Hello, world !
这样一来,顺序就完全没影响了。但是参数名和值一定要对应:
>>> hello1(greeting = ‘Hello‘, name = ‘world‘)
world, Hello !
这类使用参数名提供的参数叫做关键字参数。它的主要作用在于可以明确每个参数的作用。可以避免奇怪的函数调用。关键字参数最厉害的地方在于可以在函数中给参数提供默认值。当参数具有默认值的时候,调用的时候就可以不提供、提供一些或提供所有的参数。例:
>>> def hello2(greeting = ‘Hello‘, name = ‘world‘):
... print ‘%s, %s !‘ %(greeting, name)
...
>>> hello2()
Hello, world !
>>> hello2(greeting = ‘Greetings‘)
Greetings, world !
>>> hello2(greeting = ‘Greetings‘, name = ‘world‘)
Greetings, world !
位置参数和关键字参数是可以联合使用的。把位置参数放置在前面就可以了。如果不这样做,解释器会不知道它们到底谁是谁(也就是它们应该处的位置)。例如:
>>> def hello3(name, greeting = ‘Hello‘, punctuation = ‘!‘):
... print ‘%s %s%s‘ %(name, greeting, punctuation)
...
>>> hello3(‘Mars‘)
Mars Hello!
>>> hello3(‘Mars‘, ‘Howdy‘)
Mars Howdy!
>>> hello3(‘Mars‘, ‘Howdy‘, ‘...‘)
Mars Howdy...
>>> hello3(‘Mars‘, greeting = ‘ni hao !‘)
Mars ni hao !!
>>> hello3()
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
TypeError: hello3() takes at least 1 argument (0 given)
收集参数
用户可以给函数提供任意多的参数,在参数前面加个星号*就可以了,参数前的星号将所有值放置在同一个元组中,可以说是。例如:
>>> def print_params(*params) :
... print params
...
>>> print_params(1,2,3)
(1, 2, 3)
星号的意思就是“收集其余的位置参数”。如果不提供任何收集的元素,params就是个空元组。例:
>>> print_params1(‘Params : ‘, 1,2,3)
Params :
(1, 2, 3)
>>> print_params1(‘Nothing ! ‘)
Nothing !
()
参数收集也可以处理关键字参数,使用两个星号。当收集位置参数和收集关键字参数一起使用时,*param收集的是位置参数部分的,两个星号收集的是关键字参数部分的。例:
>>> def print_params2(**params):
... print params
...
>>> print_params2(x=1,y=2,z=3)
{‘y‘: 2, ‘x‘: 1, ‘z‘: 3}
>>> def print_params2(x, y, z=3, *paspar, **keypar):
... print x, y, z
... print paspar
... print keypar
...
>>> print_params2(1,2,3,5,6,7,foo=1,bar=2)
1 2 3
(5, 6, 7)
{‘foo‘: 1, ‘bar‘: 2}
>>> print_params2(1,2)
1 2 3
()
{}
>>> print_params2(1,2,3,5,6,7,8,9,foo=1,bar=2,foo1=3,bar1=4)
1 2 3
(5, 6, 7, 8, 9)
{‘bar1‘: 4, ‘foo‘: 1, ‘bar‘: 2, ‘foo1‘: 3}
参数收集的逆过程
刚刚已经介绍过收集参数了,那现在来介绍参数的分配,同样适用*和双星号运算符——不过是在调用而不是在定义的时候适用。
使用*运算符处理参数列表,例:
>>> def add(x,y):
... return x+y
...
>>> params = (1,2)
>>> add(*params)
3
使用**运算符处理字典参数,例:
>>> def hello2(greeting = ‘Hello‘, name = ‘world‘):
... print ‘%s, %s !‘ %(greeting, name)
...
>>> params = {‘name‘: ‘Sir Robin‘, ‘greeting‘ : ‘Well met‘}
>>> hello2(**params)
Well met, Sir Robin !
注:*和双星号只在定义函数(允许使用不定数目的参数)或者调用(“分割”字典或者序列)时才有用。
练习使用参数
>>> def story(**kwds):
... return ‘once upon a time , there was a ‘... ‘%(job)s called %(name)s.‘ %kwds
...
>>> def power(x, y, *others):
... if others:
... print ‘Received redundant parameters : ‘, others
... return pow(x, y)
...
>>> def interval(start, stop=None,step=1):
... ‘Imitates range() for step > 0‘
... if stop is None: #如果没有为stop提供值。。。。。
... start, stop=0, start #指定参数(序列解包)
... result = []
... i = start
... while i < stop:
... result.append(i)
... i+=step
... return result
...
>>> print story(job = ‘king‘, name = ‘Gumby‘)
once upon a time , there was a king called Gumby.
>>> params = {‘job‘:‘language‘, ‘name‘:‘Pythone‘}
>>> print story(**params)
once upon a time , there was a language called Pythone.
>>> del params[‘job‘]
>>> params
{‘name‘: ‘Pythone‘}
>>> print story(job=‘stroke of genius‘,**params)
once upon a time , there was a stroke of genius called Pythone.
>>> params
{‘name‘: ‘Pythone‘}
>>> power(2,3)
8
>>> power(y=3,x=2)
8
>>> params=(5,)*2
>>> power(*params)
3125
>>> power(3,3,‘Hello , world !‘)
Received redundant parameters : (‘Hello , world !‘,)
27
>>> interval(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> interval(1,5)
[1, 2, 3, 4]
>>> interval(3,12,4)
[3, 7, 11]
>>> power(*interval(3,7))
Received redundant parameters : (5, 6)
81
3.作用域
变量和所对应的值相当是个‘不可见’的字典,这类‘不可见’的字典叫做命名空间或者作用域。
屏蔽引发的问题
如果局部变量或者参数的名字和想要访问的全局变量名相同的话,就不能直接访问了。全局变量会被局部变量屏蔽。如果的确需要的话,可以使用globals函数获取全局变量,它可以返回全局变量的字典(locals返回局部变量的字典)。例:
>>> def combine(parameter):
... print parameter + globals()[‘parameter‘]
...
>>> parameter = ‘berry‘
>>> combine(‘shrub‘)
shrubberry
嵌套作用域
Python的函数是可以嵌套的,也就是说可以将一个函数放在另一个里面。例:
>>> def foo():
... def bar():
... print ‘hello , world !‘
... bar()
...
>>> foo()
hello , world !
嵌套一般来说并不是很重要,但它有一个很突出的应用,例如需要用一个函数“创建”另一个,也就意味着可以像下面这样(在其他函数内)书写函数:
>>> def multiplier(factor):
... print factor
... def multiplyByFactor(number):
... print ‘number is : ‘, number, ‘ , factor is : ‘, factor
... return number * factor
... return multiplyByFactor
...
>>> double = multiplier(2)
2
>>> double(5)
number is : 5 , factor is : 2
10
>>> multiplier(5)(4)
5
number is : 4 , factor is : 5
20
分析说明:一个函数位于另外一个里面,外层函数返回里层函数。也就是说函数本身被返回了,但并没有被调用。重要的是返回的函数还可以访问它的定义所在的作用域。每次调用外层函数,它内部的函数都被重新绑定。
递归
使用递归实现阶乘:
>>> def factorial(n):
... if n == 1:
... return 1
... return n * factorial(n-1)
...
>>> factorial(5)
120
>>> factorial(1)
1
使用递归实现幂:
>>> def power(x, n):
... if n==0:
... return 1
... return x * power(x, n-1)
...
>>> power(3,5)
243
>>> power(3,0)
1
使用递归实现二分法查找:
>>> def search(sequence, number, lower = 0, upper = None):
... if upper is None : upper = len(sequence) - 1
... if lower == upper :
... print ‘sequence[upper] is : ‘, sequence[upper]
... assert number == sequence[upper]
... return upper
... else :
... middle = (lower + upper) / 2
... print ‘middle is : ‘, middle, ‘ ; sequence[middle] is : ‘, sequence[middle]
... if number > sequence[middle] :
... return search(sequence, number, middle + 1, upper)
... else :
... return search(sequence, number, lower, middle)
...
>>> sequence = [34,67,8,123,4,100,95]
>>> sequence.sort()
>>> sequence
[4, 8, 34, 67, 95, 100, 123]
>>> search(sequence, 34)
middle is : 3 ; sequence[middle] is : 67
middle is : 1 ; sequence[middle] is : 8
middle is : 2 ; sequence[middle] is : 34
sequence[upper] is : 34
2
>>> search(sequence, 95)
middle is : 3 ; sequence[middle] is : 67
middle is : 5 ; sequence[middle] is : 100
middle is : 4 ; sequence[middle] is : 95
sequence[upper] is : 95
4
函数式编程
map
map函数可以将序列中的元素全部传递给一个函数。例:
>>> map(str, range(10))
[‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘]
filter
filter函数可以基于一个返回布尔值的函数对元素进行过滤。例:
>>> def func(x):
... return x.isalnum()
...
>>> seq = [‘faa‘, ‘fafe‘, ‘###‘, ‘***‘]
>>> filter(func, seq)
[‘faa‘, ‘fafe‘]
上述的map和filter函数都可以用列表推导式代替。
reduce
reduce函数会将序列的前两个元素与给定的函数联合使用,并且将它们的返回值和第三个元素继续联合使用,知道整个序列处理完毕,并且得到一个最终结果。
例:计算一个序列的数字的和,可以使用reduce函数加上lambda(可以创建短小的函数)x,y:x + y(继续使用相同的数字):
>>> nums = [1,2,3,4,5]
...
>>> reduce(lambda x, y : x + y, nums)
15
这里lambda x, y : x + y其实就是创建了x与y的和的短小函数。
4.本章新函数
map(func,seq[, seq, …]) 对序列中的每个元素应用函数
filter(func, seq) 返回其函数为真的元素的列表
reduce(func, seq[, initial]) 等同于func(func(func(seq[0], seq[1], seq[2], …)))
sum(seq) 返回seq中所有元素的和
apply(func[,args[, kwargs]]) 调用函数,可以提供参数
标签:
原文地址:http://blog.csdn.net/lzh398651363/article/details/51545549