函数并非总是直接显示输出,相反,它可以处理一些数据,并返回一个或者一组值。函数返回的值被称为返回值。在函数中,可使用return语句将值返回到调用函数的代码行。返回值能够将程序的大部分繁重工作移到函数中去完成,从而简化主程序。
def formatted_name(first_name, last_name):
full_name = first_name + ' ' + last_name
return full_name.title()
name = formatted_name('dana', 'hendrix')
print name
结果
Dana Hendrix
该函数的通过定义形参接收名和姓,并在名和姓之间加一个空格,把组合好之后的字符串赋值给full_name变量。
full_name变量调用title()方法把每个单词的首字母变成大写,最后返回这个字符串。通过调用该函数返回字符串并赋值给name变量。最后打印name变量所指代的值。
这样在每个需要拼接名和姓的地方。只需要调用formatted_name()函数即可。非常方便。
有时候,需要让实参变成可选的,这样使用函数就只需在必要的时候才提供额外的信息。可以使用默认值让实参变成可选的。
改变一下上面的函数,添加一个中间名。
def formatted_name(first_name, middle_name, last_name):
full_name = first_name + ' ' + middle_name + ' ' + last_name
return full_name.title()
name = formatted_name('dana', 'lee', 'hendrix')
print name
结果
Dana Lee Hendrix
然而并非所有的人都有中间名。那应该怎么做呢。没有就不让他输入。改变一下代码。
def formatted_name(first_name, last_name, middle_name = ''):
if middle_name:
full_name = first_name + ' ' + middle_name + ' ' + last_name
else:
full_name = first_name + ' ' + last_name
return full_name.title()
name = formatted_name('dana', 'hendrix' ,'lee')
name_too = formatted_name('dana', 'hendrix' )
print name
print name_too
结果
Dana Lee Hendrix
Dana Hendrix
在示例中,姓名是根据三个可能提供的部分创建的。由于人都有名和姓,因此在函数定义中首先列出这两个形参。中间名是可选的,因此在函数定义中最后列出该形参,并将其默认值设置为空字符串。
Python将非空字符串解读为True。所以在判断的时候,如果输入了中间名。判断就是成立的。所以拼接出了中间名。
函数可返回任何类型的值,包括列表和字典等较复杂的数据结构。
下面示例返回一个简单的字典
def build_person(first_name, last_name):
person = {'first': first_name, 'last': last_name}
return person
person = build_person('dana', 'hendrix')
print person
结果
{'last': 'hendrix', 'first': 'dana'}
函数接收名和姓,在函数中组成一个字典并赋值给person变量。之后返回person变量所指代的数据。
下面改变一下代码,让其也能存储age
def build_person(first_name, last_name, age=''):
if age:
person = {'first': first_name, 'last': last_name, 'age': age}
else:
person = {'first': first_name, 'last': last_name}
return person
person = build_person('dana', 'hendrix',67)
print person
结果
{'age': 67, 'last': 'hendrix', 'first': 'dana'}
修改后的函数在只输入名和姓的时候,会返回只有名和姓的字典,在age也输入的时候,会返回包含名和姓还有年龄的字典。
def build_person(first_name, last_name, age=''):
name = first_name + ' ' + last_name
return name.title()
while True:
print "\nTell me your name: "
first_name = input("First name:")
last_name = input("Last name:")
name = build_person(first_name, last_name)
print "Hello " + name
结果
Tell me your name:
First name:"dana"
Last name:"hendrix"
Hello Dana Hendrix
这个示例没有定义结束循环的语句。所以它将一直执行下去。这里只是作为演示使用。
定义函数时,经常会向函数传递列表。让函数处理列表中的数据,然后返回想要的结果。
def print_user_name(names):
for name in names:
msg = "Hello, " + name.title() + "!"
print msg
names = ['daba','devid']
print_user_name(names)
结果
Hello, Daba!
Hello, Devid!
在示例中,向函数print_user_name()传递一个名字列表。在函数中定义了循环名字列表的代码,并打印。最后直接调用该函数。就打印出了列表中的所有名字并进行打招呼。
将列表传递给函数后,函数就可以对其进行修改。在函数中对这个列表所做的任何修改都是永久性的,这能够高效的处理大量的数据。
names = ['daba','devid']
names_title = []
def update_name(names):
while names:
names_title.append(names.pop().title())
update_name(names)
print names_title
结果
['Devid', 'Daba']
该代码从names列表弹出名字,并转换为首字母大写,最后添加到names_title列表中。可以看到,在函数调用之前,names_title是一个空列表。但是函数调用之后,names_title列表中存在值了。说明函数对列表的数据进行了永久性的更改。
有时候,需要禁止函数修改列表。就是要处理这个列表的一些数据,但是还希望保留原来列表中的数据。
只需要将列表的副本传递给函数,可以像下面这样做。
update_name(names[:])
切片表示法[:]创建列表的副本。
虽然向函数传递列表的副本可保留原始列表的内容,但除非有充分的理由需要传递副本,否则还是应该将原始列表传递给函数。因为让函数使用现成的列表可避免花时间和内存创建副本,从而提高效率,在处理大列表的时候尤其如此。
有时候,预先不知道函数需要接收多少个实参,好整在Python准许函数从调用语句中收集任意数量的实参。
看一下下面的例子:
def print_user_name(*names):
print names;
print_user_name("dana")
print_user_name("dava","devid")
结果
('dana',)
('dava', 'devid')
形参名*names中的*号让Python创建一个名为names的空元组,并将收到的所有值都封装到这个元组中。这个这个函数可以处理1个值,也可以处理多个值。它以类似的方式处理不同的调用,注意,Python将实参封装到一个元组中,即便函数只收到一个值也是如此。
如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。Python先匹配位置实参和关键字实参,再将余下的实参都收集到最后一个形参中。
def print_likes(name,*fruits):
fruits_str = ""
for fruit in fruits:
fruits_str = fruits_str + " " + fruit
print name.title() + " like" + fruits_str
print_likes("dana","apple","banana")
print_likes("devid","apple")
结果
Dana like apple banana
Devid like apple
有时候,需要接收任意数量的实参,但预先不知道传递给函数的会是什么样的信息。在这种情况下,可将函数编写成能够接收任意熟练的键值对,调用语句提供多少就接受多少。
def build_profile(first_name, last_name, **user_info):
profile = {'first_name': first_name, 'last_name': last_name}
for key, value in user_info.items():
profile[key] = value
return profile
profile = build_profile('dana','hendrix',like_fruit = 'apple',like_ball = 'basketball')
print profile
结果
{'like_fruit': 'apple', 'first_name': 'dana', 'last_name': 'hendrix', 'like_ball': 'basketball'}
形参user_info中的两个星号让Python创建一个名为user_info的空字典,并将收到的所有键值对都封装到这个字典中。
在编写函数时,可以以各种方式混合使用位置实参,关键字实参和任意数量的实参。知道这些实参的类型是大有裨益的。
函数的优点之一是,使用它们可将代码块与主程序分离。通过给函数指定描述性名称,可让主程序容易理解的多。还可以更近一步,将函数存储在被称为模块的独立文件中,再将模块导入到主程序中。import语句准许在当前运行的程序文件中使用模块中的代码。
通过将函数存储在独立的文件中,可隐藏程序代码的细节,将重点放在高层逻辑上。这还能让你在不同的程序中重用函数。将函数存储在独立文件中后,可与其他的程序员共享这些文件而不是整个程序。知道如何导入函数还能让你使用其他程序员编写的函数库。
导入模块的方法有很多种,下面对每种都作简要的介绍。
要让函数是可导入的,得先创建模块。模块是扩展名为.py的文件,包含要导入到程序中的代码。
function.py
def build_profile(first_name, last_name, **user_info):
profile = {'first_name': first_name, 'last_name': last_name}
for key, value in user_info.items():
profile[key] = value
return profile
test.py
import function
profile = function.build_profile('dana','hendrix',like_fruit = 'apple',like_ball = 'basketball')
print profile
运行test文件。结果如下
{'like_fruit': 'apple', 'first_name': 'dana', 'last_name': 'hendrix', 'like_ball': 'basketball'}
Python读取这个文件时,代码行import funtion让Python打开文件fuction.py,并将其中的所有函数都复制到这个程序中。你看不到复制的代码,因为这个程序运行时,Python在幕后复制这些代码。你只需知道,在test.py中,可以使用function.py中定义的所有函数。
要调用被导入的模块中的函数,可指定导入的模块名称function和函数名build_profile,并用句号分隔它们。
这就是一种导入的方法,只需要编写一条import语句并在其中指定模块名,就可以在程序中使用该模块下面的所有函数。
还可以导入模块中特定的函数,这种导入方法的语法如下
from function import function_1
通过用逗号分隔函数名,可根据需要从模块中导入任意数量的函数
from function import function_1,function_2,function_3
使用这种语法,调用函数时就无需使用句号。是由于在import语句中显示的导入了函数。
如果要导入的函数的名称可能与程序中现有的名称冲突,或者函数的名称太长,可使用简短而独一无二的别名,函数的另一个名称,类似外号。要给函数指定这种特殊外号,需要在导入时就做。
from function import build_profile as build
profile = build('dana','hendrix',like_fruit = 'apple',like_ball = 'basketball')
print profile
还可以给模块指定别名。通过给模块指定简短的别名,能够更轻松的调用模块中的函数。
import function as fun
profile = fun.build_profile('dana','hendrix',like_fruit = 'apple',like_ball = 'basketball')
print profile
使用星号(*)运算符可让Python导入模块中的所有函数
from function import *
profile = build_profile('dana','hendrix',like_fruit = 'apple',like_ball = 'basketball')
print profile
import语句中的星号让Python将模块function中的每个函数都复制到这个程序文件中。由于导入了每个函数,可通过名称来调用每个函数,而无需用句号表示法。然而并非自己编写的大型模块时,最好不要采用这种导入方法,如果模块中有函数的名称与你的项目中使用的名称相同,可能导致意想不到的结果。Python可能遇到多个名称相同的函数或变量,进而覆盖函数,而不是分别导入所有函数。
最佳的做法是,要么导入你需要使用的函数,要么导入整个模块并使用句号表示法。这能让代码更清晰,更容易阅读和理解。