Python从入门到实践——第八章 函数 function

前言

            本章内容很多!真的是漫长的一章啊!!

            学习tips: 在学习新知识或者处理复杂逻辑/多步骤习题时,相信很多新手会陷入大脑混乱、不知所措中。新手常见的问题有:

            1. 混淆控制语句、函数和变量:控制流用于控制程序的执行流程,函数是一段可重用的代码,而变量是用于存储值的标识符。确保理解它们之间的区别对于正确编写和调用代码至关重要。

            2. 代码逻辑和调用的理解: 在一些代码示例中,新手可能遇到了一些逻辑错误,比如函数调用的位置和方式不正确。理解代码的执行流程以及函数如何被调用是至关重要的。

            3. 变量覆盖: 在代码中使用了相同的变量名来表示不同的实体,这可能导致混淆。确保变量名的一致性,不要在不同的上下文中使用相同的名称。

            4. 对特定语法和功能的理解: 比如我对函数返回值的使用和调用有些混淆,这都会阻碍我对代码的理解和使用。

            5. 语法错误和调试: 在编写代码时,可能会遇到语法错误或逻辑错误。学会使用调试工具(如 `print` 语句、调试器)来检查代码的执行流程,有助于找出错误并进行修复。

            在近八章学习中,我找到了整理清楚并且不让大脑过多负载的办法。面对全新代码时,要仔细看书中对每一个代码的解释。在看懂解释之后,在自己的大脑里用1.2.3.的方式复盘代码逻辑(可以选择写注释在代码中作为提示)。这样能够确保编写代码的独立自主性。

def formatted_name(first_name,last_name):

    formatted_name = first_name+' '+ last_name

    return formatted_name.title()

students = formatted_name('Haifei',"Wang")

print(students)



#1. 使用函数建立总体name变量

#2. 返回变量

#3. 创建一个新变量储存返回值。

            同样地,做习题时会遇到大段要求。其实要求越多,越证明题目编写者给了越多的提示。可以把一段话切分成不同点,确认自己的代码能够完成各类要求。

            【函数是什么】:函数是带名字的代码块,用于完成具体的工作。要执行函数定义的特定任务,可调用该函数。需要在程序中多次执行同一项任务时,你无需反复编写完成该任务的代码,而只需调用执行该任务的函数,让Python运行其中的代码。你将发现,通过使用函数,程序的编写、阅读、测试和修复都将更容易。

            【学什么】:你会学习向函数传递信息的方式。(1)如何编写主要任务是显示信息的函数。(2)用于处理数据并返回一个或一组值的函数。(3)将函数存储在被称为模块的独立文件中,让主程序文件的组织更为有序。

1.定义函数 def

def=definition 定义


def great_user():#定义一个函数,下方所有缩进构成函数体。

    """显示问候语:""" #文本注释,三引号,描述函数做什么。

    print("Hello!") #函数的工作

great_user() #函数调用让Python执行函数的代码。要调用函数,可依次指定函数名以及用括号括起的必要信息,

            (1)使用关键字def来告诉Python你要定义一个函数。这是函数定义,向Python指出了函数名,还可能在括号内指出函数为完成其任务需要什么样的信息。在这里,函数名为greet_user(),它不需要任何信息就能完成其工作,因此括号是空的(即便如此,括号也必不可少)。最后,定义以冒号结尾。紧跟在def greet_user():后面的所有缩进行构成了函数体。

            (2)三引号:文档字符串(docstring)的注释,描述了函数是做什么的。文档字符串用三引号括起,Python使用它们来生成有关程序中函数的文档。

            (3)代码行print("Hello!")是函数体内的唯一一行代码,greet_user()只做一项工作:打印Hello!。

            (4)要使用这个函数,可调用它。函数调用让Python执行函数的代码。要调用函数,可依次指定函数名以及用括号括起的必要信息。由于这个函数不需要任何信息,因此调用它时只需输入greet_user()即可。和预期的一样,它打印Hello!。

【向函数传递信息】

            为此,可在函数定义defgreet_user()的括号内添加username。通过在这里添加username,就可让函数接受你给username指定的任何值.

def great_user(username):#定义一个函数,下方所有缩进构成函数体。

    """显示问候语:""" #文本注释,三引号,描述函数做什么。

    print(f"Hello {username.title()}!") #函数的工作

great_user('Ashley') #函数调用让Python执行函数的代码。要调用函数,可依次指定函数名以及用括号括起的必要信息,

            代码greet_user('Ashley')调用函数greet_user(),并向它提供执行print语句所需的信息。这个函数接受你传递给它的名字,并向这个人发出问候:Hello Ashley!

【实参和形参】

            在函数greet_user()的定义中,变量username是一个形参——函数完成其工作所需的一项信息。在代码greet_user('ashley')中,值'ashley'是一个实参。实参是调用函数时传递给函数的信息。我们调用函数时,将要让函数使用的信息放在括号内。在greet_user('ashely')中,将实参'ashley'传递给了函数greet_user(),这个值被存储在形参username中。

【练习】

8-1 消息:编写一个名为display_message()的函数,它打印一个句子,指出你在本章学的是什么。调用这个函数,确认显示的消息正确无误。

def display_message():

    """本章中你学到了什么:"""

    print('Function.')

display_message()

8-2 喜欢的图书:编写一个名为favorite_book()的函数,其中包含一个名为title的形参。这个函数打印一条消息,如One of my favorite books is Alice in Wonderland。调用这个函数,并将一本图书的名称作为实参传递给它。

def favorite_book(title):

    """What's your favorite book?"""

    print(f'One of my favorite books is {title.title()}.')

favorite_book('Alice in Wonderland')

2. 传递实参

            向函数传递实参的方式很多:(1)可使用位置实参,这要求实参的顺序与形参的顺序相同;(2)也可使用关键字实参,其中每个实参都由变量名和值组成;(3)还可使用列表和字典。下面来依次介绍这些方式。

【位置实参】

def animal_lists(category,name):

    """What's your pet's name?"""

    print(f"My {category}'s name is {name.title()}.")

animal_lists('pig','feifei')

animal_lists('dog','zjk')

            该函数定义表明,需要一种动物类型和一个名字, 在函数体内,使用了这两个形参来显示宠物的信息。实参’pig’储存在动物类型中,’feifei’储存在名字中。同时,可以调用函数多次,只需再次调用animal_lists()即可。

            调用函数多次是一种效率极高的工作方式。我们只需在函数中编写描述宠物的代码一次,然后每当需要描述新宠物时,都可调用这个函数。

            位置实参的顺序很重要,不要储存错了。

【关键词实参】

            关键字实参是传递给函数的名称—值对。你直接在实参中将名称和值关联起来了,因此向函数传递实参时不会混淆(不会得到名为Pig的feifei这样的结果)。关键字实参让你无需考虑函数调用中的实参顺序,还清楚地指出了函数调用中各个值的用途。

def animal_lists(category,name):

    """What's your pet's name?"""

    print(f"My {category}'s name is {name.title()}.")

animal_lists(category='pig',name='feifei')

            关键字实参的顺序无关紧要,因为Python知道各个值该存储到哪个形参中。

def animal_lists(category,name):

    """What's your pet's name?"""

    print(f"My {category}'s name is {name.title()}.")

animal_lists(name='feifei',category='pig')

结果都是:My pig's name is Feifei.

【默认值】

            在调用函数中给形参提供了实参时,Python将使用指定的实参值;否则,将使用形参的默认值。因此,给形参指定默认值后,可在函数调用中省略相应的实参。使用默认值可简化函数调用,还可清楚地指出函数的典型用法。

def animal_lists(name, category='dog',):#把默认值放到最后。

    """clarify the information of your pet."""

    print(f"My {category}'s name is {name.title()}.")

animal_lists(name='feifei')

My dog's name is Feifei.

            报错:parameter without a default follows parameter with a default

这个错误信息通常是指在函数或方法的参数列表中,具有默认值的参数(有默认值的参数)之后跟着一个没有默认值的参数(没有默认值的参数)。这在某些编程语言中可能会导致问题,因为调用函数时,你需要先提供没有默认值的参数,然后才能提供有默认值的参数

         另外,Python依然将这个实参视为位置实参,因此如果函数调用中只包含宠物的名字,这个实参将关联到函数定义中的第一个形参。

            使用这个函数的最简单的方式是,在函数调用中只提供小狗的名字:

animal_lists('feifei')

【避免实参错误】

            读懂Traceback的报错提示。

【练习】

            8-3 T恤:编写一个名为make_shirt()的函数,它接受一个尺码以及要印到T恤上的字样。

def make_shirt(size, font):

    """Show T-shirt's information:"""

    print("\n The T-shirt's size and font are:")

    print(f"The size is {size}, and the font is {font}.")

make_shirt('Medium','Simsun')

            这个函数应打印一个句子,概要地说明T恤的尺码和字样。

            使用位置实参调用这个函数来制作一件T恤;

            再使用关键字实参来调用这个函数。

def make_shirt(size, font):

    """Show T-shirt's information:"""

    print("\n The T-shirt's size and font are:")

    print(f"The size is {size}, and the font is {font}.")

make_shirt(size='Medium',font='Simsun')

            8-4 大号T恤:修改函数make_shirt(),使其在默认情况下制作一件印有字样“I love Python”的大号T恤。调用这个函数来制作如下T恤:一件印有默认字样的大号T恤、一件印有默认字样的中号T恤和一件印有其他字样的T恤(尺码无关紧要)。

def make_shirt(size, font='I love Python'):

    """Show T-shirt's information:"""

    print(f"The T-shirt's size and font are:The size is {size}, and the font is {font}.")

make_shirt(size='Large')

make_shirt(size='Medium')

make_shirt(size='Medium',font='Simsun')

            8-5 城市:编写一个名为describe_city()的函数,它接受一座城市的名字以及该城市所属的国家。

            这个函数应打印一个简单的句子,如Reykjavik is in Iceland。

            给用于存储国家的形参指定默认值。

            为三座不同的城市调用这个函数,且其中至少有一座城市不属于默认国家。

def describe_city(name,country='China'):

    print(f"{name.title()} is in {country.title()}.")

describe_city('Beijing')

describe_city('Wuhan')

describe_city('Amsterdam','Dutch')

3. 返回值 return

            函数并非总是直接显示输出,相反,它可以处理一些数据,并返回一个或一组值。函数返回的值被称为返回值。

            在函数中,可使用return语句将值返回到调用函数的代码行。返回值让你能够将程序的大部分繁重工作移到函数中去完成,从而简化主程序。

def formatted_name(first_name,last_name):

    formatted_name = first_name+' '+ last_name

    return formatted_name.title()

students = formatted_name('Haifei',"Wang")

print(students)



#1. 使用函数建立总体name变量

#2. 返回变量

#3. 创建一个新变量储存返回值。

            调用返回值的函数时,需要提供一个变量,用于存储返回的值。在这里,将返回值存储在了变量students中。输出为整洁的姓名:Haifei Wang.

            如果还是有些困惑,不如看一下更简单的解释:

            如果我们把函数想象成一个自动售卖机,那我们购买到的饮料就是返回值。

def vending_machine(choice):

    if choice =='1':#记得加引号

        return'一瓶可乐'

    elif choice=='2':

        return'一袋薯片'

    elif choice=='3':

        return'一个雪糕'

    else:

        return'nothing'

choice=input('欢迎使用自动贩卖机,请输入编号:')

print(f'你购买的是:{vending_machine(choice)}。')

【让实参变成可选的】

def formatted_name(first_name,last_name,middle_name=' '):

    if middle_name:

        formatted_name = f'{first_name} {middle_name} {last_name}'

    else:

        formatted_name = f'{first_name} {last_name}'

    return formatted_name.title()

students = formatted_name('Haifei',"Wang")

print(students)

students = formatted_name('Haifei','Wang','Pig')#最后一个是中间名

print(students)

            Haifei   Wang

            Haifei Pig Wang

            在函数体中,我们检查是否提供了中间名。Python将非空字符串解读为True,因此如果函数调用中提供了中间名,if middle_name将为True。如果提供了中间名,就将名、中间名和姓合并为姓名,然后将其修改为首字母大写格式,并返回到函数调用行。在函数调用行,将返回的值存储在变量musician中;然后将这个变量的值打印出来 如果还要指定中间名,就必须确保它是最后一个实参,这样Python才能正确地将位置实参关联到形参。

            如果没有提供中间名,middle_name将为空字符串,导致if测试未通过,进而执行else代码块:只使用名和姓来生成姓名,并将设置好格式的姓名返回给函数调用行。在函数调用行,将返回的值存储在变量students中;然后将这个变量的值打印出来。

习题:

def func(x):

    if x<=1:

        return 1 #如果输入 x 小于等于 1,函数返回 1(这是阶乘的终止条件)。

    else:

        return xfunc(x-1) #如果输入 x 大于 1,函数返回 x 乘以 func(x-1) 的结果。

print(func(4))


#func(4) = 4  func(3)

      # = 4  3  func(2)

      # = 4  3  2  func(1)

      # = 4  3  2  1

      #= 24

【返回字典】

def build_person(first_name,last_name):

    """返回一个字典,包含一个人的信息"""

    person={'first name':first_name,'last name':last_name}

    return person

musician=build_person('haifei','wang')

print(musician)

            函数build_person()接受名和姓,并将这些值封装到字典中。

            存储first_name的值时,使用的键为'first',而存储last_name的值时,使用的键为'last'。最后,返回表示人的整个字典。

            打印这个返回的值,此时原来的两项文本信息存储在一个字典中:{'first name': 'haifei', 'last name': 'wang'}

【while循环:储存用户输入】

return储存之后,再while

def formatted_name(first_name,last_name):

        full_name = f'{first_name} {last_name} ' #不理解它的用处

        return full_name

while True:

    print('Please tell me your name:')

    f_name=input("First name:")

    l_name=input("Last name:")

    new_formatted_name=formatted_name(f_name,l_name)

    print(f"Hello, {new_formatted_name}.")

full-name相当于局部变量。

停止 if-break

def formatted_name(first_name,last_name):

        full_name = f'{first_name} {last_name} ' #不理解它的用处

        return full_name

while True:

    print('Please tell me your name:')

    print("Enter 'q' if you want to quit.")

    f_name=input("First name:")

    if f_name=='q':

        break

    l_name=input("Last name:")

    if l_name=='q':

        break

    new_formatted_name=formatted_name(f_name,l_name)

    print(f"Hello, {new_formatted_name}.")

【练习】

            8-6 城市名:编写一个名为city_country()的函数,它接受城市的名称及其所属的国家。至少使用三个城市-国家对调用这个函数,并打印它返回的值。

【报错】

#城市名:编写一个名为city_country()的函数,它接受城市的名称及其所属的国家。

# #这个函数应返回一个格式类似于下面这样的字符串

#至少使用三个城市-国家对调用这个函数,并打印它返回的值。



def city_country(city,country):

    full_name= f'{city.name()},{country.name()}'

    return full_name

    new_name=full_name('beijing','china')

print(new_name)

            处理几个问题:

            1.函数调用的语法是 function_name(argument1, argument2, ...),而不是variable_name(argument1, argument2, ...)。在你的代码中,full_name 是一个字符串,而不是一个函数,因此 full_name('beijing', 'china') 是无效的。

            2.开头大写是.title(),我总是写错成.name()

            3.你在函数内部使用了 return 语句,它会导致函数在执行到 return 时立即退出,因此后面的代码(如new_name=full_name('beijing','china'))将不会被执行。你可能想要将这些行放在函数调用之前。

            修改:

def city_country(city,country):

    full_name= f'{city.title()},{country.title()}'

    return full_name #return会立刻返回,不会接着执行后续的函数。所以new_name没有缩进

new_name=city_country('beijing','china') #必须用func函数调用。

print(new_name)

new_name=city_country('shanghai','china') #必须用func函数调用。

print(new_name)

new_name=city_country('tokyo','jepan') #必须用func函数调用。

print(new_name)

            #8-7 专辑:编写一个名为make_album()的函数,它创建一个描述音乐专辑的字典。#这个函数应接受歌手的名字和专辑名,并返回一个包含这两项信息的字典。#使用这个函数创建三个表示不同专辑的字典,并打印每个返回的值,以核实字典正确地存储了专辑的信息。

def make_album(singer,album):

    music_album={'singer name':singer,'album name':album} #'singer_name'不变。

    return music_album

list=make_album('Taylor Swift','1989')

print(list)

list=make_album('Eason Chen','淘汰')

print(list)

list=make_album('Jay Zhou','青花瓷')

print(list

            #给函数make_album()添加一个可选形参,以便能够存储专辑包含的歌曲数。如果调用这个函数时指定了歌曲数,就将这个值添加到表示专辑的字典中。调用这个函数,并至少在一次调用中指定专辑包含的歌曲数。

def make_album(singer,album,number=None):

    if number==None:

        music_album={'singer name':singer,'album name':album} 

        return music_album

    else:

        music_album={'singer name':singer,'album name':album,'number':number} 

        return music_album

album1=make_album('Taylor Swift','1989','8')

print(album1)

album2=make_album('Eason Chen','淘汰')

print(album2)

album3=make_album('Jay Zhou','青花瓷')

print(album3)

{'singer name': 'Taylor Swift', 'album name': '1989', 'number': '8'}

{'singer name': 'Eason Chen', 'album name': '淘汰'}

{'singer name': 'Jay Zhou', 'album name': '青花瓷'}

8-8 用户的专辑:在为完成练习8-7编写的程序中,编写一个while循环,让用户输入一个专辑的歌手和名称。获取这些信息后,使用它们来调用函数make_album(),并将创建的字典打印出来。在这个while循环中,务必要提供退出途径。

def make_album(singer,album,number=None):

    if number==None:

        music_album={'singer name':singer,'album name':album}

        return music_album

    else:

        music_album={'singer name':singer,'album name':album,'number':number}

        return music_album

while True:

    singer=input("请输入歌手名字(或者输入'quit'退出):")

    if singer.lower()=='quit':

        break

    album=input("请输入专辑名字:")

    number=input("请输入专辑中歌曲数量(可选择,没有请按enter键):")

    if number:

        album=make_album(singer,album,number)

    else:

        album=make_album(singer,album)

    print(album)
 

请输入歌手名字(或者输入'quit'退出):陈奕迅

请输入专辑名字:淘汰

请输入专辑中歌曲数量(可选择,没有请按enter键):

{'singer name': '陈奕迅', 'album name': '淘汰'}

请输入歌手名字(或者输入'quit'退出):Taylor

请输入专辑名字:1989

请输入专辑中歌曲数量(可选择,没有请按enter键):10

{'singer name': 'Taylor', 'album name': '1989', 'number': '10'}

请输入歌手名字(或者输入'quit'退出):quit

【加入break】的办法

            在input下一行加入if, break。

4. 传递列表

            将列表传递给函数后,函数就能直接访问其内容。下面使用函数来提高处理列表的效率。

            下面的示例将一个名字列表传递给一个名为greet_users()的函数,这个函数问候列表中的每个人。

def greating_lists(names):#建立函数 # 问候 

    '''给列表中的用户打招呼'''

    for name in names:

        print(f'Hello! {name.title()}.')

usernames=['feifei','ashley','tony']# 发送列表

greating_lists(usernames)#调用列表-实参

            在这个代码中,实参是函数调用中的 `usernames`,它传递给了 `greet_users` 函数。具体来说,`usernames` 是一个包含字符串元素的列表,即 `[‘feifei’,’tony’,’ashley’]`。这个列表被传递给 `greet_users` 函数,然后在函数内部,通过 `for` 循环遍历列表中的每个元素,并对每个元素执行一些操作,生成问候消息并打印出来。

【在函数中修改列表-两个函数】

主程序:

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

completed_models = []

print_models(unprinted_designs,completed_models)

show_completed_models(completed_models)

我们创建了一个未打印的设计列表,还创建了一个空列表,用于存储打印好的模型。接下来,由于我们已经定义了两个函数,因此只需调用它们并传入正确的实参即可。我们调用print_models()并向它传递两个列表;像预期的一样,print_models()模拟打印设计的过程。接下来,我们调用show_completed_models(),并将打印好的模型列表传递给它,让其能够指出打印了哪些模型。描述性的函数名让别人阅读这些代码时也能明白,虽然其中没有任何注释。

这个程序还演示了这样一种理念,即每个函数都应只负责一项具体的工作。第一个函数打印每个设计,而第二个显示打印好的模型;这优于使用一个函数来完成两项工作。编写函数时,如果你发现它执行的任务太多,请尝试将这些代码划分到两个函数中。别忘了,总是可以在一个函数中调用另一个函数,这有助于将复杂的任务划分成一系列的步骤。

【禁止函数修改列表】

有时候,需要禁止函数修改列表。例如,假设像前一个示例那样,你有一个未打印的设计列表,并编写了一个将这些设计移到打印好的模型列表中的函数。你可能会做出这样的决定:即便打印所有设计后,也要保留原来的未打印的设计列表,以供备案。

本来打印了之后,unprinted designs 就没了

 function_name (list_name[:]) 使用切片之后,可以保留原来的unprinted_designs

def print_models(unprinted_designs,completed_models):

    """

    模拟打印每个设计,直到没有未打印的设计为止

    打印每个设计后,都将其移到列表completed_models中

    """

    while unprinted_designs:

        current_design = unprinted_designs.pop()

        # 模拟根据设计制作3D打印模型的过程

        print("Printing model:"+current_design)

        completed_models.append(current_design)



def show_completed_models(completed_models):

    """显示打印好的所有模型"""

    print("\nThe following models have been printed:")

    for completed_model in completed_models:

        print(completed_model)



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

completed_models = []

print_models(unprinted_designs[:],completed_models)

show_completed_models(completed_models)

print(unprinted_designs)

结果:
Printing model:dodecahedron

Printing model:robot pendant

Printing model:iphone case

The following models have been printed:

dodecahedron

robot pendant

iphone case

['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

[]

虽然向函数传递列表的副本可保留原始列表的内容,但除非有充分的理由需要传递副本,否则还是应该将原始列表传递给函数,因为让函数使用现成列表可避免花时间和内存创建副本,从而提高效率,在处理大型列表时尤其如此。

【练习】

8-9 魔术师:创建一个包含魔术师名字的列表,并将其传递给一个名为show_magicians()的函数,这个函数打印列表中每个魔术师的名字。

def show_magicians(magicians):

    for magician in magicians:

        print(magician)



if __name__ == "__main__":

    # 创建包含魔术师名字的列表

    magicians_list = ["feifei", "ashley", "tony"]



    # 调用show_magicians()函数并传递列表

    print("魔术师列表:")

show_magicians(magicians_list)

8-10 了不起的魔术师:在你为完成练习8-9而编写的程序中,编写一个名为make_great()的函数,对魔术师列表进行修改,在每个魔术师的名字中都加入字样“the Great”。调用函数show_magicians(),确认魔术师列表确实变了。

def show_magicians(magicians):

    for magician in magicians:

        print(magician)

def make_great_magicians(magicians):

    for i in range(len(magicians)):

        magicians[i]=f'The Great {magicians[i]}.'

        print(magicians[i])



if __name__ == "__main__":

    # 创建包含魔术师名字的列表

    magicians_list = ["feifei", "ashley", "tony"]

    # 调用show_magicians()函数并传递列表

    print("原始魔术师列表:")

    show_magicians(magicians_list)

    print("新的魔术师列表:")

    make_great_magicians(magicians_list)

    # 调用show_magicians()函数显示修改后的魔术师列表
8
-11 不变的魔术师:修改你为完成练习8-10而编写的程序,在调用函数make_great()时,向它传递魔术师列表的副本。由于不想修改原始列表,请返回修改后的列表,并将其存储到另一个列表中。分别使用这两个列表来调用show_magicians(),确认一个列表包含的是原来的魔术师名字,而另一个列表包含的是添加了字样“the Great”的魔术师名字。
def show_magicians(magicians):

    for magician in magicians:

        print(magician[:])

def make_great_magicians(magicians):

    for i in range(len(magicians)):

        magicians[i]=f'The Great {magicians[i]}.'

        print(magicians[i])



if __name__ == "__main__":

    # 创建包含魔术师名字的列表

    magicians_list = ["feifei", "ashley", "tony"]

    # 调用show_magicians()函数并传递列表

    print("原始魔术师列表:")

    show_magicians(magicians_list)

    print("新的魔术师列表:")

    make_great_magicians(magicians_list)

    # 调用show_magicians()函数显示修改后的魔术师列表

print("最初魔术师列表:")

show_magicians(magicians_list[:])

原始魔术师列表:

feifei

ashley

tony

新的魔术师列表:

The Great feifei.

The Great ashley.

The Great tony.

最初魔术师列表:

The Great feifei.

The Great ashley.

The Great tony.

5.传递任意数量的实参(*)

有时候,你预先不知道函数需要接受多少个实参,好在Python允许函数从调用语句中收集任意数量的实参。

def feifei_behaviors(*behavior):#通过加星号调用多个函数

    print(f'飞飞正在:{behavior}')

feifei_behaviors('拉粑粑')

feifei_behaviors('吃粑粑','吃屎','被茵茵看着拉屎')

下面的函数只有一个形参*behavior,但不管调用语句提供了多少实参,这个形参都将它们统统收入囊中。

def feifei_behaviors(*behaviors):#通过加星号调用多个函数

    print(f'飞飞正在:')

    for behavior in behaviors:

        print(f'    {behavior}')

feifei_behaviors('拉粑粑')

feifei_behaviors('吃粑粑','吃屎','被茵茵看着拉屎')

飞飞正在:

    拉粑粑

飞飞正在:

    吃粑粑

    吃屎

    被茵茵看着拉屎

不管收到的是一个值还是三个值,这个函数都能妥善地处理。

【结合使用位置实参和任意数量实参】

def behaviors(name,*behaviors):#通过加星号调用多个函数

    print(f'{name}正在:')

    for behavior in behaviors:

        print(f'    {behavior}')

behaviors('Tony','学习')

behaviors('飞飞','吃粑粑','吃屎','被茵茵看着拉屎')

基于上述函数定义,Python将收到的第一个值存储在形参name中,并将其他的所有值都存储在元组behaviors中。在函数调用中,首先指定表示name的实参,然后根据需要指定任意数量的行为。

【使用任意数量的关键字实参】

你知道你将收到有关用户的信息,但不确定会是什么样的信息。在下面的示例中,函数build_profile()接受名和姓,同时还接受任意数量的关键字实参:

我们将名和姓加入到这个字典中,因为我们总是会从用户那里收到这两项信息。

之后,我们遍历字典user_info中的键—值对,并将每个键—值对都加入到字典profile中。最后,我们将字典profile返回给函数调用行。

def build_profile(first,last,**user_info):#**可变关键字参数,除了First和last

    """创建一个字典,其中包含我们知道的有关用户的一切"""

    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)
 

编写函数时,你可以以各种方式混合使用位置实参、关键字实参和任意数量的实参。

【练习】

8-12 三明治:

#编写一个函数,它接受顾客要在三明治中添加的一系列食材。这个函数只有一个形参(它收集函数调用中提供的所有食材),

# 并打印一条消息,对顾客点的三明治进行概述。

# 调用这个函数三次,每次都提供不同数量的实参。

def pizza(*toppings):

    print("The pizza contains:")

    for topping in toppings:

        print(f'{topping}')

pizza('Baconic')

pizza('Baconic','Fruit')

pizza('Baconic','Fruit','Chicken')

8-13 用户简介:复制前面的程序user_profile.py,在其中调用build_profile()来创建有关你的简介;调用这个函数时,指定你的名和姓,以及三个描述你的键-值对。

def build_profile(first,last,**user_info):#**可变关键字参数,除了First和last

    """创建一个字典,其中包含我们知道的有关用户的一切"""

    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('Ashhley','Zhang',

                             age='22',

                             field='public heath')

print(user_profile)

8-14 汽车:编写一个函数,将一辆汽车的信息存储在一个字典中。这个函数总是接受制造商和型号,还接受任意数量的关键字实参。这样调用这个函数:提供必不可少的信息,以及两个名称—值对,如颜色和选装配件。

#8-14 汽车:编写一个函数,将一辆汽车的信息存储在一个字典中。

# 这个函数总是接受制造商和型号,还接受任意数量的关键字实参。

# 这样调用这个函数:提供必不可少的信息,以及两个名称—值对,如颜色和选装配件。


def car_profile(producer,type,**user_info):#**可变关键字参数,除了First和last

    """创建一个字典,其中包含我们知道的有关用户的一切"""

    profile = {}

    profile['producer'] = producer

    profile['type'] = type

    for key,value in user_info.items():

        profile[key] = value

    return profile

user_profile = car_profile('BMW','5-generation',

                             color='white',

                             cost='10w')

print(user_profile)

6. 将函数存储在模块中

函数的优点之一是,使用它们可将代码块与主程序分离。通过给函数指定描述性名称,可让主程序容易理解得多。你还可以更进一步,将函数存储在被称为模块的独立文件中,再将模块导入到主程序中。import语句允许在当前运行的程序文件中使用模块中的代码。

【导入整个模块import】无需冒号

可以在另一个文件里 通过import直接调取(文档直接使用和迁移) 不需要冒号

【导入特定的函数 from import】

from module_name import function_name: 

pizza.py文件中:

def lababa(name,numbers):

    """概述要制作的比萨"""

    print(f"{name} 拉了质量为{numbers}kg的粑粑。")

def study(name, hours):

    print(f"{name} 学了{hours}小时。")

建立一个新文件:

import pizza #调用pizza程序

pizza.lababa('feifei','2')#调用lababa方法

pizza.study('tony','24') #调用study方法

feifei 拉了质量为2kg的粑粑。

tony 学了24小时。

from pizza import lababa #调用pizza程序中的lababa方法

lababa('feifei','2')#调用lababa方法

lababa('godfly','10')#调用lababa方法

feifei 拉了质量为2kg的粑粑。

godfly 拉了质量为10kg的粑粑。

【给函数指定别名 from import as】

如果要导入的函数的名称可能与程序中现有的名称冲突,或者函数的名称太长,可指定简短而独一无二的别名——函数的另一个名称,类似于外号。要给函数指定这种特殊外号,需要在导入它时这样做。

from pizza import lababa as lb #调用pizza程序中的lababa方法

lb('feifei','2')#调用lababa方法

lb('godfly','10')#调用lababa方法

【给模块指定别名 import as】

p. function

import pizza as p #改变模块的名字

p.lababa('feifei','2')#调用lababa方法

p.lababa('godfly','10')#调用lababa方法

【导入模块中的所有函数*】

from pizza import *

然而,使用并非自己编写的大型模块时,最好不要采用这种导入方法:如果模块中有函数的名称与你的项目中使用的名称相同,可能导致意想不到的结果:Python可能遇到多个名称相同的函数或变量,进而覆盖函数,而不是分别导入所有的函数。

最佳的做法是,要么只导入你需要使用的函数,要么导入整个模块并使用句点表示法。

7. 函数编写指南

(1)所有的import语句都应放在文件开头,唯一例外的情形是,在文件开头使用了注释来描述整个程序。

(2)应给函数指定描述性名称,且只在其中使用小写字母和下划线。描述性名称可帮助你和别人明白代码想要做什么。给模块命名时也应遵循上述约定。每个函数都应包含简要地阐述其功能的注释,该注释应紧跟在函数定义后面,并采用文档字符串格式。

(3)给形参指定默认值时,等号两边不要有空格。

user_profile = car_profile('BMW','5-generation',

                             color='white',

                             cost='10w')

对于函数调用中的关键字实参,也应遵循这种约定:

animal_lists(category='pig',name='feifei')

(4)长度与缩进:

PEP 8(https://www.python.org/dev/peps/pep-0008/)建议代码行的长度不要超过79字符,这样只要编辑器窗口适中,就能看到整行代码。如果形参很多,导致函数定义的长度超过了79字符,可在函数定义中输入左括号后按回车键,并在下一行按两次Tab键,从而将形参列表和只缩进一层的函数体区分开来。

(5)如果程序或模块包含多个函数,可使用两个空行将相邻的函数分开,这样将更容易知道前一个函数在什么地方结束,下一个函数从什么地方开始。

【练习】

8-15 打印模型:

#8-15 打印模型:将示例print_models.py中的函数放在另一个名为printing_functions.py的文件中;

# 在print_models.py的开头编写一条import语句,并修改这个文件以使用导入的函数。

import printing_function as pf

pf.lababa('ashley')

pf:

def lababa(name):

    print(f'{name}正在拉粑粑')

lababa('godfly')

8-16 导入:选择一个你编写的且只包含一个函数的程序,并将这个函数放在另一个文件中。在主程序文件中,使用下述各种方法导入这个函数.

#import module_name

#from module_name import function_name

#from module_name import function_name as fn

#import module_name as mn

#from module_name import *

import printing_function

printing_function.lababa('ashley')


from printing_function import lababa

lababa('ashley')


from printing_function import lababa as lb

lb('ashley')


import printing_function as pf

pf.lababa('ashley')


from printing_function import*

lababa('ashley')

8-17 函数编写指南:选择你在本章中编写的三个程序,确保它们遵循了本节介绍的函数编写指南。

小结

            在本章中,你学习了:

        (1)如何编写函数,以及如何传递实参,让函数能够访问完成其工作所需的信息;

        (2)如何使用位置实参和关键字实参,以及如何接受任意数量的实参;

        (3)显示输出的函数和返回值的函数;如何将函数同列表、字典、if语句和while循环结合起来使用。

        (4)你还知道了如何将函数存储在被称为模块的独立文件中,让程序文件更简单、更易于理解。

        (5)最后,你学习了函数编写指南,遵循这些指南可让程序始终结构良好,并对你和其他人来说易于阅读。

            程序员的目标之一是,编写简单的代码来完成任务,而函数有助于你实现这样的目标。它们让你编写好代码块并确定其能够正确运行后,就可置之不理。确定函数能够正确地完成其工作后,你就可以接着投身于下一个编码任务。

            (1)多次使用:函数让你编写代码一次后,想重用它们多少次就重用多少次。需要运行函数中的代码时,只需编写一行函数调用代码,就可让函数完成其工作。需要修改函数的行为时,只需修改一个代码块,而所做的修改将影响调用这个函数的每个地方。

            (2)容易阅读:使用函数让程序更容易阅读,而良好的函数名概述了程序各个部分的作用。相对于阅读一系列的代码块,阅读一系列函数调用让你能够更快地明白程序的作用。

            (3)函数还让代码更容易测试和调试:如果程序使用一系列的函数来完成其任务,而其中的每个函数都完成一项具体的工作,测试和维护起来将容易得多:你可编写分别调用每个函数的程序,并测试每个函数是否在它可能遇到的各种情形下都能正确地运行。经过这样的测试后你就能信心满满,深信你每次调用这些函数时,它们都将正确地运行。

            

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值