1.函数
def hello(name): #使用def定义函数
return 'Hello,'+name+'!'
print(hello('World'))
文档字符串(在函数开头写下的字符串):会作为函数的一部分进行存储
def square(x):
'Caculates the square of the number x.'
return x*x
print(square.__doc__) #以.__doc__的方式访问文档字符串(__doc__是函数属性)
help(square) #内建的help函数:可以得到关于函数及它的文档字符串信息
Python中所有函数都有返回值(如果没有返回值,则会返回None)
def test():
print('this is printed')
return #在Python中有时候可以没有return语句,或者虽然有return语句但return后边没有跟任何值
#此时的return语句只起到跳出函数的作用
x=test()
print("test():",x)
2.函数参数
2.1.位置参数
形式参数(形参):写在def语句中函数名后面的变量,存储在局部作用域内
实际参数(实参):调用函数时提供的值,又称为值
在函数内赋予新值不会改变外部任何变量的值
def try_to_change(n):
n="Mr.Gumby"
name="Mrs.Entity"
try_to_change(name)
print(name)
#其工作方式类似于:
name="Mrs.Entity"
n=name
n="Mr.Gumby"
print(name)
可变的数据结构(如:列表)用作参数时,其值会被改变
def change(n):
n[0]='Mr. Gumby'
names=['Mrs.Entity','Mrs.Thing']
change(names)
print(names) #返回值为:['Mr. Gumby', 'Mrs.Thing']
因为当两个变量同时引用一个列表时,通过一个变量改变了列表的值,则另一个变量访问到的就是改变后的值
如果想避免这种情况的出现,可以复制一个列表的副本(names[:]):
def change(n):
n[0]='Mr. Gumby'
names=['Mrs.Entity','Mrs.Thing']
change(names[:]) #此时的change函数不会影响到names的值
print(names) #返回值为:['Mrs.Entity', 'Mrs.Thing']
使用函数改变数据结构(如列表或字典)是将程序抽象化的好方法
def init(data): #字典初始化
data['first']={}
data['middle']={}
data['last']={}
storage={}
init(storage)
print(storage) #{'first': {}, 'middle': {}, 'last': {}}
def lookup(data,label,name): #查找名字(列表名,标签,名字)
return data[label].get(name)
def store(data,full_name):
names=full_name.split() #拆分full_name
if len(names)==2:names.insert(1,'') #如果没有中间名,则插入空字符串
labels='first','middle','last'
for label,name in zip(labels,names): #使用zip函数联合标签和名字
people=lookup(data,label,name)
if people:
people.append(full_name) #如果对应first、middle、last的键值已经存在,就把全名添加进去
else:
data[label][name]=[full_name] #键不存在时,自动添加键值
MyNames={}
init(MyNames)
store(MyNames,'Robin Hood')
store(MyNames,'Robin Locksley')
print(lookup(MyNames,'first','Robin')) #['Robin Hood', 'Robin Locksley']
在Python中,函数只能修改参数对象本身,而不能重绑定参数来影响函数外的变量
只能选择从函数中返回所有需要的值(如果有多个,则以元组的形式返回)
def inc(x): #将变量+1
return x+1
foo=10
foo=inc(foo)
print(foo) #11
或选择将值放在列表中进行处理:
def inc(x): #将变量+1
x[0]=x[0]+1
foo=[10]
inc(foo)
print(foo) #[11]
2.2关键字参数
调用函数时提供参数的名字可以明确每个参数的作用,避免弄混参数顺序
def hello_1(greeting,name):
print('%s,%s!'%(greeting,name))
hello_1('World','Hello') #World,Hello!
hello_1(name='World',greeting='Hello') #Hello,World!
关键字参数也可以在函数中给参数提供默认值
提供默认值后,调用函数时可以选择不提供、提供一些或提供全部的参数
def hello_2(greeting='Hello',name='World'):
print('%s,%s!' %(greeting,name))
hello_2('Greetings') #Greetings,World!
hello_2(name='World') #Hello,World!
hello_2('Greeting','Universe') #Greeting,Universe!
位置参数可以和关键字参数联合使用(位置参数放在关键字参数前)
注:1.除非完全清楚程序的功能和参数的意义,否则应该避免混合使用位置参数和关键字参数
2.一般来说,只有在强制要求的参数个数比所给参数的个数少时才使用
def hello_3(name,greeting='Hello',punctatuation="!"):
print('%s,%s%s' %(greeting,name,punctatuation))
hello_3('Greetings',punctatuation=".") #Hello,Greetings.
2.3收集参数
Python还可以让用户提供任意多的参数(有时候让用户提供任意数量的参数是很有用的)
def print_params(*params):
print(params)
print_params(1,2,3) #(1, 2, 3)
print_params() #()
参数前的*号能将其余的位置参数收集起来放置在一个元组中
如果不提供任何可供收集的元素,则会是个空元组
联合普通参数使用:
def print_params_2(title,*params):
print(title)
print(params)
print_params_2('Params:',1,2,3) #Params:
#(1, 2, 3)
处理关键字参数:
def print_param_3(x,y,z=3,*pospar,**keypar):
print(x,y,z)
print(pospar)
print(keypar)
print_param_3(1,2,3,4,5,6,7,foo=1,bar=2) #1 2 3
# (4, 5, 6, 7)
# {'foo': 1, 'bar': 2}
#实现多个名字同时存储
def init(data):
data['first']={}
data['middle']={}
data['last']={}
storage={}
init(storage)
print(storage) #{'first': {}, 'middle': {}, 'last': {}}
def lookup(data,label,name):
return data[label].get(name)
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]
MyNames={}
init(MyNames)
store(MyNames,'Luke Skywalker','Anakin Skywalker')
print(lookup(MyNames,'last','Skywalker')) #['Luke Skywalker', 'Anakin Skywalker']
2.4反转过程
分配参数:在调用函数时使用*号可以实现函数收集的逆过程
def add(x,y):return x+y
param=(1,2)
print(add(*param)) #3
使用**号运算符来处理字典
def hello(greeting='Hello',name='World'):
print('%s,%s!' %(greeting,name))
params={'name':'Sir Robin','greeting':'Wellmet'}
hello(**params) #Wellmet,Sir Robin!
注:*号只在定义和调用函数时才有用
def with_stars(**kwds):print(kwds['name'],'is',kwds['age'],'years old')
def without_stars(kwds):print(kwds['name'],'is',kwds['age'],'years old')
args={'name':'Mr.Gumby','age':42}
with_stars(**args) #Mr.Gumby is 42 years old
without_stars(args) #Mr.Gumby is 42 years old
2.5参数练习
def story(**kwds):
return 'Once upon a time, there was a '\
'%(job)s called %(name)s.' %kwds
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.
def power(x,y,*others):
if others:
print('Received redundant parameters:',others)
return pow(x,y)
print(power(3,2)) #9
print(power(y=3,x=2)) #8
params=(5,)*2
print(power(*params)) #3125
power(3,3,'Hello,World') #Received redundant parameters: ('Hello,World',)
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(interval(10)) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(interval(1,5)) #[1, 2, 3, 4]
print(interval(3,12,4)) #[3, 7, 11]
power(*interval(3,7)) #Received redundant parameters: (5, 6)
3.作用域
在Python中,变量和所对应的值用的是一个“不可见”的字典,可以用内建函数vars来返回该字典
一般来说,vars所返回的字典是不能修改的
x=1
print(vars()['x']) #1
vars()['x']+=1
print(x) #2
这类“不可见”的字典叫做命名空间(作用域)
除全局作用域外,每个函数调用都会创建一个新的作用域(函数内的变量称为局部变量)
可以在函数内部访问全局变量来获取它的值(此方法是很多错误的引发原因,请慎重使用)
def combine(parameter):
print(parameter+external)
external='berry'
combine('Shrub') #Shrubberry
如果局部变量和想要访问的全局变量名相同的话,还可以通过globals函数获取全局变量的值
def combine(parameter):
print(parameter+globals()['parameter'])
parameter='berry'
combine('Shrub') #Shrubberry
当局部变量和全局变量重名时,在函数内部可以通过global将局部变量声明为全局变量从而对全局变量进行操作
x=1
def change_global():
global x #声明x为全局变量
x=x+1
change_global()
print(x) #2
嵌套作用域:Python函数是可以嵌套的,可以用一个函数创建另一个
def multiplier(factor):
def multiplyByFactor(number):
return number*factor
return multiplyByFactor
triple=multiplier(2)
print(triple(5)) #10
print(multiplier(5)(4)) #20
外层函数返回里层函数,返回的函数可以访问它定义所在的作用域
类似mltiplyByFactor函数存储子封闭作用域的行为叫做闭包
外层函数的变量一般来说是不能重新赋值的,但在Python 3.0中,nonlocal关键字可以让用户对外部作用域(但并非全局作用域)的变量进行赋值
def multiplier(factor):
factor=3
def multiplyByFactor(number):
nonlocal factor
return number*factor
return multiplyByFactor
print(multiplier(2)(5)) #15
4.递归
有用的递归函数一般包含下面几部分:
1.当函数直接返回值时有基本实例(最小可能性问题)
2.递归实例,包括一个或者多个问题最小部分的递归调用
递归不能永远继续下去,它总是要以最小可能性问题结束
当函数调用“自身”时,实际上运行的是两个不同的函数(同一个函数具有两个不同的命名空间)
#n的阶乘
def factorial(n):
if n==1:
return 1
else:
return n*factorial(n-1)
print(factorial(10)) #3628800
大多数情况下,递归可以用循环来代替,而且更高效(递归更易读)