7.Python函数

1.定义一个函数

定义一个函数需要5个部分:

  • def告诉Python,用户在自定义函数
  • function_name告诉Python要定义的函数的名字,且取名尽量做到descriptive
  • (parameters)这是形式参数,简称形参,接收函数调用时,传过来的实参,不需要传参时可省略
  • '''docstring'''不执行任何功能,仅用来说明函数功能,调用函数者可以查看该函数的docstring以了解其功能
  • function_body是函数的主体,函数要实现的功能由它决定

格式:

#函数定义
def function_name(parameters):  #注意冒号
    '''docstring''' #注意缩进1个tab
    function_body   #注意缩进1个tab

#函数调用   
function_name(arguments)    #arguments为实参,字符串参数要加引号

2.参数

在上述的函数定义格式中,有两种参数,分别是:parametersarguments

parameters为形式参数,简称为形参在函数定义时,仅作为符号,表示这里应该有这样一个参数,实现函数的成功定义。

arguments实参,即主程序中,需要调用函数处理的实实在在的信息。调用时,会实现parameter_1=argument_1...,将所有实参的值赋给对应的形参,交由函数处理。

例:

输入:

def greet_user(username):
    '''display a simple greeting'''
    print('hello, '+username.title()+'!')
    
greet_user('jack')

输出:

c:\py>function_define
hello, Jack!

3.传送多个参数

上面的例子是仅传一个参数的情况,parameters和arguments可以有多个,有3种方法实现多参数传送。

(1) 位置实参

def语句

def function_name(parameter_1, parameter_2,..., parameter_n):

调用函数语句

function_name(argument_1, argument_2,..., argument_n):

调用函数语句中的实参与def语句中的形参按顺序一一对应,传参时实现的操作如下:

parameter_1=argument_1
parameter_2=argument_2
.
.
.
parameter_n=argument_n

注意,使用位置实参时,一定要按照定义函数时,正确的顺序排列,不然会出错。

(2) 关键字实参

关键字传参是将一个name-value组合传给函数形参。

调用形式:
function_name(name_1=value_1,name_2=value_2,...,name_n=value_n)

name-value里面,name为函数定义时,形参的名字,value为主程序中实参的值,通过name=value实现传参。所以通过关键字实参传参,并不需要按照定义时的顺序。

输入:

def describe_pet(animal_type,pet_name):
    '''display information about a pet'''
    print('\nI have a '+animal_type+'.')
    print('My '+animal_type+"'s name is "+pet_name+'.')

describe_pet(animal_type='dog',pet_name='harry')
#顺序不一样
describe_pet(pet_name='harry',animal_type='dog')

输出:

c:\py>describe_pet.py

I have a dog.
My dog's name is harry.

I have a dog.
My dog's name is harry.

上面程序调用了两次describe_pet函数,参数顺序不一样,但是输出结果一样。

(3) 默认值

当一个函数被调用时,它的某些参数总是很少改变时,我们可以给这些很少变动的参数,在定义函数时,给它们一个默认值。这样在调用函数时,若与默认值相同,则可以不用写该参数的实参值,直接采用默认值,如果与默认值不符,可以用关键字name-value对传参。

输入:

def describe_pet(pet_name,animal_type='dog'):       #默认animal_type参数值为‘dog’
    '''display information about a pet'''
    print('\nI have a '+animal_type+'.')
    print('My '+animal_type+"'s name is "+pet_name+'.')

describe_pet(pet_name='harry')  #省略animal_type参数值
describe_pet('harry')   #采用位置实参传参

describe_pet(animal_type='cat',pet_name='tom') #与默认值不符,用name-value对传参

输出:

c:\py>describe_pet.py

I have a dog.
My dog's name is harry.

I have a dog.
My dog's name is harry.

I have a cat.
My cat's name is tom.

注意: 所有带有默认值的参数必须放在没有默认值的参数后面,不然程序会报错。

错误示例:

def describe_pet(animal_type='dog',pet_name):   

输出:

c:\py>describe_pet.py
  File "C:\py\describe_pet.py", line 1
    def describe_pet(animal_type='dog',pet_name):  

把带默认值的参数放最后,这样也可以使用位置实参来传送参数,忽略后面有默认值的形参,剩下的与调用语句中的实参一一对应。

(4) 可选实参

我们可以在定义函数时,把可选参数的默认值设为空optional argument='',这样在调用函数时,即使没有对应的实参,也不会因为实参与形参数量不匹配而报错。

输入:

def get_formatted_name(first_name,last_name,middle_name=''):        #给middle_name赋值为空
    '''return a full name,neatly formatted.'''
    if middle_name:
        full_name=first_name+' '+middle_name+' '+last_name
    else:
        full_name=first_name+' '+last_name
    return full_name.title()

musician = get_formatted_name('jimmi','fallon')
print(musician)
    
musician = get_formatted_name('jimmi','fallon','lee')   #lee放最后,与middle_name相对应
print(musician)

输出:

c:\py>get_formatted_name2
Jimmi Fallon
Jimmi Lee Fallon

注意: 上例中的middle_name的默认值为空字符串,因为有默认值,要把它放到最后。Python认为空字符串的值为0,所以if检测到空字符串,即if=0,条件不成立,if下面缩进的语句不执行,转而执行else下面缩进的语句。

4.返回值

Python可以返回任意类型的值。

(1) 返回简单值

我们调用函数后,在函数末尾使用return语句,可以返回被调用的函数中需要的值;在主程序中,可以使用一个赋值语句接收返回值。

输入:

def get_formatted_name(first_name,last_name):
    '''return a full name, neatly formatted.'''
    full_name = first_name+' '+last_name
    return full_name.title()
musician = get_formatted_name('jimmy','logan') #用musician来接收返回值
print(musician)

输出:

c:\py>get_formatted_name.py
Jimmy Logan

(2) 返回字典

输入:

def get_formatted_name(first_name,last_name):
    '''return a dictionary of information about a person.'''
    person={'first':first_name , 'last':last_name}
    return person
    
musician = get_formatted_name('jimmy','logan')
print(musician)

输出:

c:\py>get_formatted_name.py
{'first': 'jimmy', 'last': 'logan'}

5.处理列表

(1) 传递列表

可以将一部分列表处理流程分离出来,作为函数,此时,函数中的形参应该是一个列表,在函数中,也作为一个列表进行处理。在主程序中,传送的实参也必须是一个列表。

输入:

def greet_users(names): 
    '''Print a simple greeting to each user in the list.'''
    for name in names:
        msg = 'hello, '+name.title()+'!'
        print(msg)

usernames=['jack','tom','lucy']
greet_users(usernames)

输出:

c:\py>greet_users
hello, Jack!
hello, Tom!
hello, Lucy!

(2) 调整列表

调用函数处理列表,给列表带来的变化是永久的。

没有使用函数的程序:

#Start with some designs that need to be printed.
unprinted_designs = ['iphone case' , 'robot pendant' , 'dodecahedron']
completed_models = []

#Simulate printing each design, until none are left.
#Move each design to completed_models after printing.
while unprinted_designs:
    current_design=unprinted_designs.pop()
    #Simulate creating a 3D print from the design.
    print('printing model: '+current_design)
    completed_models.append(current_design)

#Display all completed models.
print("\nThe following models have been printed : ")
for completed_model in completed_models:
    print(completed_model)

输出:

c:\py>print_model
printing model: dodecahedron
printing model: robot pendant
printing model: iphone case

The following models have been printed :
dodecahedron
robot pendant
iphone case

我们可以把print_modelsshow_completed_models作为两个函数封装起来。

使用函数的程序:

def  print_models(unprinted_designs,completed_models):
#Simulate printing each design, until none are left.
#Move each design to completed_models after printing.
    while unprinted_designs:
        current_design=unprinted_designs.pop()
        #Simulate creating a 3D print from the design.
        print('printing model: '+current_design)
        completed_models.append(current_design)

def show_completed_models(completed_models):
#Display all completed models.
    print("\nThe following models have been printed : ")
    for completed_model in completed_models:
        print(completed_model)
        
#Start with some designs that need to be printed.
unprinted_designs = ['iphone case' , 'robot pendant' , 'dodecahedron']
completed_models = []

print("\nunprinted_designs : "+str(unprinted_designs)+'\n')
print_models(unprinted_designs,completed_models)
show_completed_models(completed_models)
print("\ncompleted_models : "+str(completed_models))

输出:

c:\py>print_model

unprinted_designs : ['iphone case', 'robot pendant', 'dodecahedron']

printing model: dodecahedron
printing model: robot pendant
printing model: iphone case

The following models have been printed :
dodecahedron
robot pendant
iphone case

completed_models : ['dodecahedron', 'robot pendant', 'iphone case']

注意: 调用函数处理列表,给列表带来的变化是永久的,就算函数里的形参列表名与主程序中的实参列表名不一致,实参列表依然与形参列表同步变化。

(3) 用切片使函数不改变列表

function_name(list_name[:])

list_name[:]将列表复制一份,作为参数传给函数,所有的操作只会改变切片,不会改变列表本身。

上例中如果我们不想改变unprinted_designs[:]列表,我们可以用下面的语句来调用函数。

print_models(unprinted_designs[:],completed_models)

6.特殊的传参情况

(1) 传递任意数量参数

def function_name( *parameters )

在定义函数时,给形参名字前面加上一个‘ * ’号,这时,python会建立一个与形参名同名的元组,将调用函数时传过来的实参,统统保存到元组中。

输入:

def make_pizza(*toppings):
    '''print the list of toppings that have been requested.'''
    print(toppings)

make_pizza('pepperoni')
make_pizza('mushrooms','green peppers','extra cheese')

输出:

c:\py>make_pizza
('pepperoni',)
('mushrooms', 'green peppers', 'extra cheese')

(2) 同时传送位置实参与任意数量实参

和带默认值的形参一样,接收任意数量实参的参数放在位置参数后面

输入:

def make_pizza(size,*toppings):
    '''summarize the pizza we are about to make.'''
    print('\nmaking a '+str(size)+'-inch pizza with the following toppings')
    for topping in toppings:
        print('- '+topping)

make_pizza(16,'pepperoni')
make_pizza(12,'mushrooms','green peppers','extra cheese')

输出:

c:\py>make_pizza

making a 16-inch pizza with the following toppings
- pepperoni

making a 12-inch pizza with the following toppings
- mushrooms
- green peppers
- extra cheese

(3) 同时传送位置实参和任意数量关键字实参

只在传送不定数量的关键字实参时使用。

def function_name( **parameters )

在定义函数时,给形参名字前面加上一个‘ ** ’号,这时,python会建立一个与形参名同名的字典,将调用函数时传过来的实参nam-value对,以name作为键,以value作为值,保存到字典中。

用“ ** ”表示任意数量关键字参数,并将任意数量关键字实参放在最后

输入:

def build_profile(first,last,**user_info):
    '''build a dictionary containing everything we know about a user.'''
    profile = {}
    profile['first_name'] = first
    profile['last_name'] = last
    for key,value in user_info.items():
        profile[key] = value
    return profile
user_profile = build_profile('albert','einstein',
                                                location='princeton',
                                                field='physics')
print(user_profile)

输出:

c:\py>build_profile
{'first_name': 'albert', 'last_name': 'einstein', 'location': 'princeton', 'field': 'physics'}

7.while语句和函数

输入:

def get_formatted_name(first_name,last_name):
    '''return full name'''
    person=first_name+' '+last_name
    return person

while True:
    print('\nplease tell me your name:')
    print("(enter 'q' to quit)")
    f_name=input('First_name : ')
    if f_name == 'q':       #输入q退出程序
        break
    l_name=input('Last_name : ')
    if l_name == 'q':
        break
    formatted_name = get_formatted_name(f_name,l_name)
    print("Full_name : "+formatted_name)

输出:

c:\py>get_formatted_name

please tell me your name:
(enter 'q' to quit)
First_name : jimmy
Last_name : logan
Full_name : jimmy logan

please tell me your name:
(enter 'q' to quit)
First_name : tao
Last_name : ming
Full_name : tao ming

please tell me your name:
(enter 'q' to quit)
First_name :

使用while,我们可以循环调用函数。

8.模块

将函数存储在不同的文件中,可以让我们忽略程序执行的一些细节,只关注更高的逻辑。

原程序:

def make_pizza(size,*toppings):
    '''summarize the pizza we are about to make.'''
    print('\nmaking a '+str(size)+'-inch pizza with the following toppings')
    for topping in toppings:
        print('- '+topping)

make_pizza(16,'pepperoni')
make_pizza(12,'mushrooms','green peppers','extra cheese')

将函数make_pizza作为模块独立出来。

如下:

def make_pizza(size,*toppings):
    '''summarize the pizza we are about to make.'''
    print('\nmaking a '+str(size)+'-inch pizza with the following toppings')
    for topping in toppings:
        print('- '+topping)

将主程序文件和模块文件放在同一个目录下。

(1) 用import导入整个模块

格式: import module_name

主程序:

import pizza        #导入整个pizza模块

pizza.make_pizza(16,'pepperoni')  #
pizza.make_pizza(12,'mushrooms','green peppers','extra cheese')

输出:

making a 16-inch pizza with the following toppings
- pepperoni

making a 12-inch pizza with the following toppings
- mushrooms
- green peppers
- extra cheese

import pizza语句会让Python将pizza模块中所有代码复制到主程序开头,使主程序可以使用pizza模块中,所有的函数。

注意: 直接导入整个模块,调用pizza模块中的函数时,需要用一个‘ . ’将模块名和函数名间隔开,格式如下:

module_name.function_name()

(2)导入特定的函数

格式:from module_name import function_name

此时调用函数时不需要‘ . ’来隔开模块名与函数名。

输入:

from pizza import make_pizza        #只导入pizza模块中的make_pizza函数

make_pizza(16,'pepperoni')
make_pizza(12,'mushrooms','green peppers','extra cheese')

输出:

making a 16-inch pizza with the following toppings
- pepperoni

making a 12-inch pizza with the following toppings
- mushrooms
- green peppers
- extra cheese

输出与上面的例子相同。

注意: 由于此时只导入特定的函数,所以主程序调用时,不加‘.’号来表示模块中的某个函数。

(3) 使用as给函数起别名

如果导入的函数的名字与主程序中的函数名冲突,又或者导入的函数名太长,我们可以用关键字as给函数起个别名,主程序可以用别名调用函数。

格式:from module_name import function_name as alias

输入:

from pizza import make_pizza as mp  #给make_pizza函数起别名为mp

mp(16,'pepperoni')      #使用mp调用函数
mp(12,'mushrooms','green peppers','extra cheese')

其输出与上例相同。

(4) 使用as给模块起别名

格式:import module_name as alias

输入:

import pizza as p   #给pizza模块起别名为p

p.make_pizza(16,'pepperoni')        #使用mp调用函数
p.make_pizza(12,'mushrooms','green peppers','extra cheese')

输出与上例相同。

给模块起简单的别名,可以简化程序,让程序作者将注意力放在描述性强的函数名上。

注意: 这种方法起别名,调用函数时。依然要用‘ . ’将别名与函数名分开。

(5) 导入模块中所有的函数(不推荐)

格式:from pizza imporet *

输入:

from pizza  import *    #导入所有pizza模块中的函数

make_pizza(16,'pepperoni')
make_pizza(12,'mushrooms','green peppers','extra cheese')

输出与上例相同。

导入模块中所有的函数后,我们调用函数,就不需要写模块名和‘ . ’,直接使用函数名,但是,如果模块中有和主程序函数名冲突的,往往会造成不可预料的错误。所以不推荐这种导入方法。

9.函数编写风格

(1) 函数的参数赋值,‘=’号两边不留空格

默认值: def function_name(parameter_0,parameter_1='default value')

关键字实参: function_name(value_0,parameter_1='value_1')

(2) 参数字符超过79个

当参数过多时,我们可以将参数拆成多行。

格式:

def function_name(
        parameter_0,parameter_1,parameter_2,        #前面两个tab
        parameter_3,parameter_4,parameter_5):       #前面两个tab
    function body       #前面一个tab
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345