Python基础教程(第2版)第六章 抽象

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

        大多数情况下,递归可以用循环来代替,而且更高效(递归更易读)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值