1、函数 def function(arg)
def fibs(num):
result =[0,1]
for i in range(num-2):
result.append(result[-2] + result[-1])
return result
>>> fibs(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
2、记录函数:在函数的开头写下字符串,作为函数的一部分进行存储,称为文档字符串
def square(x):
'Calculates the square of the number x.'
return x*x
文档字符串的访问方式:
>>> square.__doc__ #__doc__是函数属性,属性名中的双下划线表示它是个特殊属性
'Calculates the square of the number x.'
>>> help(square) #内建的help函数非常有用
Help on function square in module __main__:
square(x)
Calculates the square of the number x.
3、函数的参数
形参:写在def语句中函数名后面的变量通常叫做函数的形式参数;
实参:调用函数的时候,提供的值是实际参数。
在函数内为参数赋予新值不会改变外部任何变量的值
参数储存在局部作用域(local scope)内
>>> def try_to_change(n):
n='JACK'
>>> name = 'Tom'
>>> try_to_change(name)
>>> name
'Tom'
3.1
#字符串(以及数字和元组)是不可变的,即无法被修改(也就是说只能用新的值覆盖)
#列表用作参数的改变:
# 函数的局部名称--包括参数在内---并不和外面的函数名称(全局的)冲突。
对于可改变的数据结构,如列表,参数的内部赋值会改变外部变量的值
内部参数与外部变量指向同一个列表,所以会被修改
若不想改变外部列表,可以传进一个副本
>>> def change(n):
n[0]='1'
>>> names= ['2','3','4']
>>> change(names) #参数被改变
>>> names
['1', '3', '4']
#采用普通方法进行模拟
>>> names = ['2','3','4']
>>> n=names #模拟传参行为
>>> n[0]='1' #改变列表
>>> names
['1', '3', '4']
3.2修改参数
例:用名字、中间名或姓查找联系人的程序
若名字为'Magus Lie Hetland'存储格式类似
data = {
'first': { 'Magus': 'Magus Lie Hetland'},
'middle': {'Lie': 'Magus Lie Hetland'},
'last': {'Hetland': 'Magus Lie Hetland'}
}
注意insert(index,value)函数,在列表的索引位置插入值
>>> def init(data): #data作为存储表,初始化
data['first']={}
data['middle']={}
data['last']={}
>>> storage ={}
>>> init(storage)
>>> storage
{'middle': {}, 'last': {}, 'first': {}}
>>> def store(data,full_name): #存储,将全名存储到表中
names = full_name.split() #将名字按空格(即first,middle,last)分开,返回列表,如'jack wang feng' 返回【'jack','wang','feng'】
if len(names)==2: names.insert(1, '') #如果names的长度为2(只有首名和末名),插入一个空字符串作为中间名,如无中间名【'tom','ping'】返回【'tom','','ping'】
labels = 'first','middle','last' #元组
for label,name in zip(labels,names): #元组与序列间也可使用zip
people = lookup(data ,label,name)
if people:
people.apend(full_name)
else:
data[label][name]=[full_name]
# 获得名字的函数:
>>> def lookup(data,label,name):
return data[label].get(name)
#输出
>>> MyNames = {}
>>> init(MyNames)
>>> store(MyNames, 'Magnus Lie Hetland')
>>> lookup(MyNames, 'middle','Lie')
['Magnus Lie Hetland']
3.3 不可变的数字和可改变的参数
>>> def inc(x): return x+1 #将变量的数值增1的函数如下:
>>> foo=10
>>> inc(foo)
11
>>> foo #外部变量未发生变化
10
>>> foo=inc(foo) #将foo重新赋值
>>> foo
11
#改变参数,将值放置在列表中 (使用列表外部变量foo改变了)
>>> def inc(x): x[0]=x[0]+1
>>> foo=[10]
>>> inc(foo)
>>> foo
[11]
3.4 关键字参数和默认值
位置参数:如下例子,如果参数有多个,参数的顺序很难记起。
>>> def hello(greeting,name):
print('%s,%s!' %(greeting,name))
>>> hello('hello','world')
hello,world!
关键字参数:使用参数名提供的参数叫做关键字参数。使用于大程序,关键字参数就是提供一个默认值
>>> def hello(greeting,name):
print('%s,%s!' %(greeting,name))
>>> hello(name='world',greeting='hello') #关键字参数最厉害的地方在于可以在函数中给参数提供默认值
hello,world!
# 关键字参数和位置参数可以混合使用,注意把位置参数放置在前面就可以。
函数的调用方式:
>>> def hello_1(name,greeting='Hello',punctuation='!'):
print('%s,%s%s' %(greeting,name,punctuation))
>>> hello_1('Mars')
Hello,Mars!
>>> hello_1('WSF','Howdy')
Howdy,WSF!
>>> hello_1('WSF','Howdy','....')
Howdy,WSF....
>>> hello_1('WSF',punctuation='.')
Hello,WSF.
>>> hello_1('WSF',greeting='Top of the morning to ya')
Top of the morning to ya,WSF!
>>> hello_1()
Traceback (most recent call last):
File "<pyshell#17>", line 1, in <module>
hello_1()
TypeError: hello_1() takes at least 1 positional argument (0 given)
3.5 收集参数
给函数提供任意多的参数
>>> def print_params(*params): #参数前的星号将所有值放置在同一个元组中,将这些值收集起来
print(params)
>>> print_params('Testing')
('Testing',) #结果作为元组打印出来
#用来联合普通参数,星号的意思就是收集其余的位置参数
>>> def print_params_2(title,*params): # *返回的是元组
print(title)
print(params)
>>> print_params_2('params:',1,2,3)
params:
(1, 2, 3)
>>> print_params_2('Nothing:') #不提供任何供收集的元素,params就是个空元组
Nothing:
()
>>> print_params_2('Hmm...',something=42) #不能处理关键字参数
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
print_params_2('Hmm...',something=42)
TypeError: print_params_2() got an unexpected keyword argument 'something'
>>> def print_params_3(**params): #处理关键字参数收集操作,**返回的是字典
print(params)
>>> print_params_3(x=1,y=2,z=3) #返回字典而不是元组
{'y': 2, 'x': 1, 'z': 3}
>>> def print_params_4(x,y,z=3,*pospar,**keypar):
print(x,y,z)
print(pospar)
print(keypar)
>>> print_params_4(1,2,3,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
()
{}
完整例子:实现多个名字同时存储
>>> def store(data,*full_names):
for full_name in full_names:
names=full_name.split()
if len(names)==2: names.insert(1,'')
labels = 'first','middle','last'
for label,name in zip(labels,names):
people =lookup(data,label,name)
if people:
people.append(full_name)
else:
data[label][name]=[full_name]
3.6 反转过程
收集参数的反转过程——在调用时使用*或**,将参数分配到定义的参数中,用于字典或列表分割时
用于列表:
>>> def add(x,y):return x+y
>>> params=(1,2)
>>> add(*params)
3
用于字典:
>>> def hello(name, greeting):
print('%s, %s!' %(greeting,name))
>>> params={'name': 'Sir Robin','greeting': 'Well met'}
>>> hello(**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:
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,
>>> print(story(name='Sir Robin', job = 'brave knight'))
Once upon a time,there was a brave knight called Sir Robin,
>>> params = {'job': 'language', 'name': 'Python'}
>>> print(story(**params)) #调用时分割字典,定义中收集
Once upon a time,there was a language called Python,
>>> del params['job']
>>> print(story(job='stroke of genius', **params))
Once upon a time,there was a stroke of genius called Python,
>>> power(2,3)
8
>>> power(3,2)
9
>>> power(y=3,x=2)
8
>>> params = (5,) * 2 #即(5,5)
>>> power(*params) #先分割,在赋给x,y
3125
4、作用域
作用域:"不可见字典"叫做命名空间或者作用域。
局部变量:函数内的变量称为局部变量(local variable)
>>> def output(x):
print(x)
>>> x=1
>>> y=2
>>> output(y)
2
在函数内部访问全局变量,会引发错误,慎重使用全局变量
>>> def combine(parameter):
print(parameter+external)
>>> external = 'berry'
>>> combine('Shrub')
Shrubberry
若全局变量与局部变量名字相同,会被局部变量覆盖,可使用global()类似vars(),获得全局变量的字典
>>> def combine(parameter):
print(parameter + globals()['parameter'])
>>> parameter='berry' #全局变量
>>> combine('Shrub')
Shrubberry
重绑定全局变量,(使变量引用其他新值)--函数内部声明全局变量,用global语句申明
>>> x=1
>>> def change_global():
global x
x = x + 1
>>> change_global()
>>> x
2
嵌套作用域--一个函数放在另一个函数里面
外部作用域中的变量一般不能被改变,但是用闭包,每次调用外层函数,内部函数都会被重新绑定,也即外部作用域factor每次都有一个新值
>>> def multiplier(factor):
def multiplyByFactor(number):
return number*factor
return multiplyByFactor #返回一个函数,这时并未调用
>>> double = multiplier(2) #double是一个函数
>>> double(5) #调用multiplyByFactor(number)
10
>>> triple = multiplier(3)
>>> triple(3)
9
>>> multiplier(5)(4)
20
5、递归:函数调用自身
阶乘
n的阶乘定义为n*(n-1)*(n-2)*....*1
循环的实现形式:
>>> def factorial(n):
result = n
for i in range(1,n):
result *=i
return result
>>> factorial(6)
720
用递归的实现:
>>> def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n-1)
>>> factorial(6)
720
幂:像内建的pow函数或者××运算符一样
power(x,n) (x为n的幂次)是x自乘n-1次的结果(所以x用作乘数n次)
循环实现:
>>> def power(x,n):
result =1
for i in range(n):
result *=x
return result
>>> power(3,3)
27
递归实现:
>>> def power(x,n):
if n ==0:
return 1
else:
return x*power(x,n-1)
>>> power(3,4)
81
二元查找
递归实例——二元搜索
前提:排好序
若上下限相同,则那就是数字所在位置,返回;
否则,找到两者的中间,查找数字是在左侧还是右侧,继续查找数字所在的那半部分。
>>> def search(sequence,number,lower,upper):
if upper is None: upper = len(sequence)-1
if lower==upper:
assert number == sequence[upper]
return upper
else:
middle = (lower+upper)//2
if number > sequence[middle]:
return search(sequence,number,middle+1,upper)
else:
return search(sequence,number,lower,middle)
>>> seq = [34,67,8,123,4,100,95]
>>> seq.sort()
>>> seq
[4, 8, 34, 67, 95, 100, 123]
>>> search(seq,34)
2