抽象函数
抽象函数可以节省很多工作,实际上它的作用还要更大,它能使计算机程序可以让人读得懂得关键。
创建函数
创建函数是组织程序的关键。那么怎么定义函数?如下:
def hello(name):
return "hello," + name + "!"
print(hello("world"))
"D:Program Filespython.exe" "E:/py_code/day 11/爬虫.py"
hello,world!
Process finished with exit code 0
运行这段程序就会得到一个名为hello的新函数,它可以返回一个将输入的参数作为名字的问候语。可以像使用内建函数一样使用它:
print(hello(gumby))
下面我们可以用函数写一个斐波那契数列的函数:
def fibs(num):
result = [0,1]
for i in range(num-2):
result.append(result[-2] + result[-1])
return result
print(fibs(9))
执行这段语句后,编译器就知道如何计算斐波那契。
参数
函数被定义后,所操作的值是从哪里来呢?一般来说,在写def语句中函数名后面的变量通常叫做函数的形参,而调用函数时提供的值是实参,或者称为参数。
- 不可变的参数
def try_to_change(n):
n = "Mr.Gumby"
return n
name = "Mrs.Entity"
print(try_to_change(name))
print(name)
"D:Program Filespython.exe" "E:/py_code/day 11/爬虫.py"
Mr.Gumby
Mrs.Entity
Process finished with exit code 0
上述的函数执行结果可以知道,当变量n改变的时候,变量name不变。同样,当在函数内部把参数重新绑定的时候,函数外部的变量不会受到影响。参数存储在局部作用域中。
- 可变的的参数
字符串(以及数字和元祖)是不可变的,即无法被修改(也就是说只能用新值去覆盖)。所以它们做参数的时候也就无需多做介绍。但是考虑一下如果将可变的数据结构如列表用作参数的时候会发生什么:
def change(n):
n[0] = "Mr.Gumby"
return n
name = ["Mrs","Entity","Thing"]
print(change(name))
print(name)
"D:Program Filespython.exe" "E:/py_code/day 11/爬虫.py"
['Mr.Gumby', 'Entity', 'Thing']
['Mr.Gumby', 'Entity', 'Thing']
Process finished with exit code 0
上述的结果可以看出,参数被改变了,这就是和上个函数很重要的区别。前面的函数中,局部变量被赋予了新值,但是这个例子中变量names所绑定的列表的确被改变了。
为什么要修改参数
使用函数改变数据结构(比如列表或字典)是一种将程序抽象化的好方法。假设需要需要编写一个存储名字并且能用名字、中间名或姓查找联系人的程序,可以使用下面的数据结构:
storage = {}
storage["first"] = {}
storage["middle"] = {}
storage["last"] = {}
storage这个数据结构是带有3个键“first”、“middle”和“last”的字典,每个键下面都又存储一个字典。子字典中、可以使用名字(名字、中间名或姓)作为键,插入联系人列表作为键。如下:
storage = {}
storage["first"] = {}
storage["middle"] = {}
storage["last"] = {}
me = "Magnue Lie Hetland"
storage["first"]["Magnue"] = [me]
storage["middle"]["Lie"] = [me]
storage["last"]["Hetland"] = [me]
print(storage)
"D:Program Filespython.exe" "E:/py_code/day 3/while.py"
{'first': {'Magnue': ['Magnue Lie Hetland']}, 'middle': {'Lie': ['Magnue Lie Hetland']}, 'last': {'Hetland': ['Magnue Lie Hetland']}}
Process finished with exit code 0
按照上述的方式如果要加入很多姓名相同的人时,因为需要扩展已经存储了那些名字的列表。如果要写个大程序来这样更新列表,那么很显然程序很快就会变得臃肿且笨拙不堪了。这个过程可以使用函数实现。下面的例子就是初始化数据结构的函数:
def init(data):
deta["first"] = {}
data["middle"] = {}
data["last"] = {}
上面的代码只是把初始化语句放到函数中,使用方法如下:
storage = {}
init(storage)
print(storage)
"D:Program Filespython.exe" "E:/py_code/day 3/while.py"
{'first': {}, 'middle': {}, 'last': {}}
Process finished with exit code 0
可以看到,函数包办了初始化的工作,让代码更易读。
在编写存储名字的函数前,先写个获得名字的函数:
def look(data,labe,name):
retuan data[label].get(name)
标签(比如“middle”)以及名字(比如“lie”)可以作为参数提供给lookup函数使用,这样会获得包含全名的列表。换句话,如果我的名字已经存储了,可以像下面这样做:
lookup(storage."middle","Lie")
"D:Program Filespython.exe" "E:/py_code/day 3/while.py"
[magnus Lie Hetland]
Process finished with exit code 0
这里需要注意,返回的列表和存储在数据结构中的列表是相同的,所以如果列表被修改了,那么也会影响数据结构(没有查询到人的时候就问题不大了,因为函数返回的是None).
def stor(data,full_name):
names = full_name.split()
if len(anmes) == 2:names.insert(1,"")
labels = "first","middle","last"
for label,name in zip(labels,name)
people = lookup(data,lable,name)
if people:
people.append(full_name)
else:
data[label][name] = [full_name]
分析:
store函数执行以下步骤。
(1)使用参数data和full_name进入函数,这两个参数被设置为函数在外部获得的一些值。
(2)通过拆分full_name,得到一个叫做names的列表。
(3)如果names的长度为2(只有首名和末名),那么插入一个空字符串作为中间名。
(4)将字符串“first”、“middle”和“last"作为元祖存储在labels中
(5)使用zip函数联合标签和名字,对于每一个(lable,name)对,进行以下处理:
a.获得属于给定标签和名字的列表;
b.将full_name添加到列表中,或者插入一个需要的新列表
MyNames = {}
init(MyName)
store(MyNames,"Magnus Lie Hetland")
lookup(MyNames,"middle","Lie")
"D:Program Filespython.exe" "E:/py_code/day 3/while.py"
["Magnus Lie Hetland"]
Process finished with exit code 0
可以看到已经可以进行运作,在进一步:
store(MyName,"Robin Hood")
store(MyName,"Robin Locksley")
lookup(MyNames,"first","Robin")
"D:Program Filespython.exe" "E:/py_code/day 3/while.py"
["Robin Hood","Robin Locksley"]
Process finished with exit code 0
store(MyName,"Mr.Gumby")
lookup(MyNames,"middle","")
"D:Program Filespython.exe" "E:/py_code/day 3/while.py"
["Robin Hood","Robin Locksley","Mr.Gumby"]
Process finished with exit code 0
可以看到,如果某些人的名字、中间名或姓相同,那么结果中会包含所有这些人的信息。
参数不可变
在某些语言中(比如C++、Pascal和Ada) 中,重新绑定参数并且使这些改变影响导函数外的变量是很常见的事情。但在Python中这是不可能的:函数只能修改参数对象本身。但是如果你的参数不可变(比如是数字),又该怎么办呢?不好意思,没有办法。这个时候你应该从函数中返回所有你需要的值(如果值多余一个的话就以元祖形式返回)。例如,将变量的数值增1的函数可以这样写:
def inc(x):
pass
return x+1
foo=10
foo=inc(foo)
print(foo)
"D:Program Filespython.exe" "E:/py_code/day 3/while.py"
11
Process finished with exit code 0