《Python从入门到实践》第八章 函数

本文围绕Python函数展开,介绍了函数定义、传递信息(形参和实参)、传递实参的方式(位置、关键字、默认值)、返回值、传递列表、任意数量实参等内容。还讲解了将函数存储在模块中,以及不同的导入方式,最后给出了函数编写的指南。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

定义函数: def

def greet_user():
    """显示简单的问候语"""
    print("Hello!")

greet_user()

关键字def是函数定义:

在上面的代码中,函数名是greet_user(),它不需要任何信息就能完成工作,因此括号内是空的(但是括号不能少),最后定义以冒号结尾。

第二行的文本是文档字符串,描述了函数是做什么的,三个双引号能够包含多行。

向函数传递信息:

def greet_user(username):
    """显示简单的问候语"""
    print(f"Hello,{username.title()}!")

greet_user("jim")

形参和实参:

在上面的代码中,username是一个形参,即函数完成工作所需的信息

greet_user("jim")中的"jim"是实参,在这个示例中,我们将实参“jim”赋给了形参username

练习8.2

def favorite_book(book_name):
    print(f"One of my favorite book is {book_name.title()}")

favorite_book("daling")

传递实参:

①位置实参

在调用函数时,Python必须将函数调用中的每个实参关联倒函数定义中的一个形参,最简单的方式是基于实参的顺序进行关联,以这种方式关联的实参称为位置实参。

def describe_pet(animal_type,pet_name):
    print(f"I have a {animal_type}")
    print(f"{animal_type}'s name is {pet_name}")

describe_pet('smoye','haha')

一个函数可以调用多次,在函数中,可根据需要使用任意数量的位置实参,Python将按顺序将函数调用中的实参关联到函数定义中相应的形参。

位置实参的顺序很重要!

②关键字实参

关键字实参是传递给函数的名值对,这样回直接在实参中将名称和值关联起来,因此向函数传递实参时就不会混淆了,关键字实参不仅让你无序考虑函数调用中的实参顺序,而且清楚地指出了函数调用中各个值的作用。

def describe_pet(animal_type,pet_name):
    """显示动物的信息"""
    print(f"I have a {animal_type}")
    print(f"{animal_type}'s name is {pet_name}")

describe_pet(pet_name = 'hali', animal_type='hasik')

在使用关键字实参时,务必准确地指定函数定义中的形参名

③默认值

在编写函数时,可以给每个形参指定默认值。如果在调用函数中给形参提供了实参,Python将使用指定的实参值,否则,将使用形参的默认值。

def describe_pet(pet_name, animal_type='hasiki'):
    """显示动物的信息"""
    print(f"I have a {animal_type}")
    print(f"{animal_type}'s name is {pet_name}")

describe_pet(pet_name = 'hali')

注意:当使用默认值时,必须在形参列表中先列出没有默认值的形参,再列出有默认值的形参,这让Python依然能够正确地解读位置实参

函数调用有很多形式,使用哪种调用方式无关紧要,只要函数调用能生成你期望的输出就好

对于

def describe_pet(pet_name, animal_type='dog')

下列的函数调用是等效的:

# 一条名为while的小狗
describe_pet('while')
describe_pet(pet_name='while')
# 一只名为Harry的仓鼠
describe_pet('Harry','hamster')
describe_pet(pet_name='harry', animal_type='hamster')
describe_pet(animal_type='hamster',pet_name='harry')

如果再待用函数的时候少了实参,系统会报错

练习8.3:

def make_shirt(size,sentence):
    print(f"this is a {size} shirt with {sentence} on it")

练习8.4:

def make_shirt(size='big',sentence='I love Python'):
    print(f"this is a {size} shirt with {sentence} on it")

返回值

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

def get_formatted_name(first_name,last_name):
    """返回标准格式的姓名"""
    full_name = f"{first_name} {last_name}"
    return full_name.title()

musician = get_formatted_name('jimi','hendrix')
print(musician)

让实参变成可选的:

有时候,需要让实参变成可选的,以便使用函数的人只在需要时才提供额外的信息。可以使用默认值来让实参变成可选的。

def get_formatted_name(first_name,last_name,middle_name = ''):
    """返回标准格式的姓名"""
    if middle_name:
        full_name = f"{first_name} {middle_name} {last_name}"
    else:
        full_name = f"{first_name} {last_name}"
    return full_name.title()

musician = get_formatted_name('jimi','hendrix')
print(musician)

musician = get_formatted_name('john','hooker','lee')
print(musician)

可以选择是否有中间名,可选值让函数能够处理各种不同情形的同时,确保函数调用尽可能简单。

返回字典

函数可以返回任何类型的值,包括列表和字典等较为复杂的数据结构。

def build_person(first_name, last_name):
    """返回一个字典,其中包含有关一个人的名i在"""
    person = {'first': first_name, 'last': last_name}
    return  person

musician = build_person('jimi','hendrix')
print(musician)

有选择性的输入年龄:

def build_person(first_name, last_name,age=None):
    """返回一个字典,其中包含有关一个人的名i在"""
    person = {'first': first_name, 'last': last_name}
    if age:
        person['age']=age
    return  person

musician = build_person('jimi','hendrix',27)
print(musician)

其中None表示变量没有值,可以视为一个占位符

结合使用函数和while循环:

def get_formatted_name(first_name, last_name):
    """返回规范格式的名字"""
    full_name = f"{first_name} {last_name}"
    return full_name.title()

while True:
    print("\nPlease tell me your name: ")
    print("enter 'q' at anytime to quit")
    f_name = input("First name:\n")
    if f_name == 'q':
        break
    l_name = input("Last name:\n")
    if l_name == 'q':
        break
    formatted_name = get_formatted_name(f_name,l_name)
    print(f"Hello, {formatted_name}")

练习8.6

def city_country(city_name,country_name):
    fact = f"{city_name},{country_name}"
    return fact
situation = city_country('shanghai','China')
print (situation)

练习8.7

def make_album(singer_nmae, album_name, song_number=None):
    albums = {'singer': singer_nmae, 'ablum': album_name}
    if song_number:
        albums['number'] = song_number
    return albums

albums1 = make_album('zhoujielun', 'qilixiang',2)
print(albums1)

练习8.8

def make_album(singer_nmae, album_name, song_number=None):
    albums = {'singer': singer_nmae, 'ablum': album_name}
    if song_number:
        albums['number'] = song_number
    return albums


print("任意时候输入'q'退出循环")
while True:
    singer1 = input('请输入歌手的名字\n')
    if singer1 == 'q':
        break
    albumname1 = input('请输入专辑的名字\n')
    if albumname1 == 'q':
        break
    album1 = make_album(singer1, albumname1)
    print(album1)

传递列表

def greet_users(names):
    """向列表中的每个用户发出简答的问候"""
    for name in names:
        msg = f"Hello,{name.title()}"
        print(msg)
usernames = ['xiongjiajin', 'zhonghangyu', 'laijiawen']
greet_users(usernames)

在函数中修改列表

unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
completed_models = []
# 模拟打印每个设计,知道没有未打印的设计为止
while unprinted_designs:
    current_design = unprinted_designs.pop()
    print(f"Printing model:{current_design}")
    completed_models.append(current_design)

print("\nThe following models have been printed:")
for completed_model in completed_models:
    print(completed_model)

也可以重新组织这些代码,编写两个函数,让每个都做一件具体的工作。大部分代码与原来相同,只是结构更为合理。第一个函数负责处理打印设计的工作,第二个概述打印了哪些设计:

def print_models(unprinted_designs, completed_designs):
    while unprinted_designs:
        current_design = unprinted_designs.pop()
        print(f"Printing model:{current_design}")
        completed_designs.append(current_design)

def show_completed_models(completed_designs):
    print("The following models have been printed:")
    for completed_design in completed_designs:
        print(completed_design)

unprinted_designs = ['phone case', 'robot pendant', 'ipad']
completed_designs = []
print_models(unprinted_designs,completed_designs)
show_completed_models(completed_designs)

禁止列表修改函数:

可向函数传递列表的副本而不是原始列表

要将列表的副本传递给函数,可以像下面这样做:

function_name(list_name[:])

切片表示法[:]创建列表的副本,并不会影响列表本身

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

练习8.9:

messages = ['what are you doing',
            'what can I say',
            'elephant in the room'
            ]
def print_messages(messages_list):
    for message in messages_list:
        print(message)

print_messages(messages)

练习8.10:

messages = ['what are you doing',
            'what can I say',
            'elephant in the room'
            ]
sent_messages = []
def print_messages(messages_list):
    for message in messages_list:
        print(message)

def send_messages(messages, sent_messages):
    while messages:
        current_message = messages.pop()
        sent_messages.append(current_message)


print_messages(messages)
send_messages(messages, sent_messages)
print(messages)
print(sent_messages)

练习8.11:

messages = ['what are you doing',
            'what can I say',
            'elephant in the room'
            ]
sent_messages = []
def print_messages(messages_list):
    for message in messages_list:
        print(message)

def send_messages(messages, sent_messages):
    while messages:
        current_message = messages.pop()
        sent_messages.append(current_message)


print_messages(messages)
sttend_messages(messages[:], sent_messages)
print(messages)
print(sent_messages)

传递任意数量的实参

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

例如一个制作披萨的函数,它需要接受很多配料,但无法预先确定顾客要点多少种配料。下面的函数只有一个形参 *toppings,不管调用语句提供了多少实参,这个形参都会将其收入囊中。

def make_pizza(*toppings):
    print(toppings)

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

还可以将函数调用print()替换为一个循环,遍历配料列表并对顾客点的披萨进行描述:

def make_pizza(*toppings):
    print("Making a pizza with the following toppings:")
    for topping in toppings:
        print(f"- {topping}")

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

不管函数收到多少个实参,这种语法都管用

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

如果要让函数接受不同类型的实参,必须在函数定义中将接纳如意数量实参的形参放在最后

例如:

def make_pizza(size,*toppings):
    print(f"Making a {size} inch pizza with the following toppings:")
    for topping in toppings:
        print(f"- {topping}")

make_pizza(12,'pepperoni')
make_pizza(18, 'green peppers', 'extra cheese')

基于上述函数定义,Python将收到的第一个值赋给形参size,将其他所有的值都存储在元组toppings中。

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

有时候,你需要接受任意数量的实参,但预先不知道传递给函数的是什么样的信息,在这种情况下,可将函数编写成能够接受任意数量的键值对——调用语句提供了多少就接受多少。

def build_profile(first, last, **user_info):
    user_info['first_name'] = first
    user_info['last_name'] = last
    return user_info

user_profile = build_profile('xiong', 'jaijin', location = 'jiangxi', field = 'civil')
print(user_profile)

tip:你经常会看到形参名**kwargs,它用于收集任意数量的关键字实参

练习8.12:

def make_pizza(*toppings):
    print("make your pizza with the following toppings:")
    for topping in toppings:
        print(f"-{topping}")

make_pizza('mushrooms','tomatoes','potatoes')
make_pizza('mushrooms')
make_pizza('fish','beef')

练习8.13:

def build_profile(first, last, **user_info):
    user_info['first_name'] = first
    user_info['last_name'] = last
    return user_info

user_profile = build_profile('xiong', 'jaijin',
                             location = 'jiangxi', field = 'civil',
                             hometown = 'ganzou')
print(user_profile)

练习8.14:

def car_info(factory, stratage, **other_info):
    other_info['factory'] = factory
    other_info['stratage'] = stratage
    return other_info

car1 = car_info('bmw', 'x4',price=14000, year=2009)
print(car1)

函数定义中使用到的参数必须为形参

将函数存储在模块中:

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

导入整个模块

模块是拓展名为.py的文件,包含要导入程序的代码

例如:将make_pizza函数放在pizza.py文件当中,然后再pizza.py相同文件夹中创建另一个文件,引入pizza模块,再使用其中的函数

import pizza
pizza.make_pizza(16,'mushroom')
pizza.make_pizza(12,'mushrooms','green peppers','extra cheese')

使用模块中的公式,可采用以下公式:

module_name.function_name()

导入特定的函数

还可以只导入模块中的特定函数:

from module_name import function_name

用逗号分隔函数名,可以根据需要从模块中导入任意数量的函数

from module_name import function_0, function_1, function_2

例:

from pizza import make_pizza

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

如果使用这种句法,在调用函数时则无需使用句点,由于在import语句中显式地导入了make_pizza()函数,因此在调用时只需指定其名称即可

使用as给函数指定别名

如果要导入的函数的名称太长或者可能与程序中既有的名称冲突,可指定简短而独一无二的别名:函数的另一个名称,类似于外号。

from pizza import make_pizza as mp

mp(16, 'pepperoni')
mp(12,'mushroom', 'green peppers', 'extra cheese')

上面的import语句将函数make_pizza()重命名为mp()。在这个程序中,每当需要调用make_pizza()时,都可将其简写成mp()。Python将运行make_pizza()中的代码,同时避免与程序可能包含的make_pizza()函数混淆

指定别名的通用语法如下:

from module_name import function_name as fn

使用as给模块指定别名

import pizza as p
p.make_pizza(16,'mushroom')
p.make_pizza(12,'mushrooms','green peppers','extra cheese')

这样让代码更加简洁,还让你不用再关注模块名,只专注于描述性的函数名

给模块指定别名的通用语法如下:

import module_name as mn

导入模块中的所有函数(谨慎使用)

使用(*)运算符可以让Python导入模块中的所有函数:

from pizza import *
make_pizza(16, 'mushroom')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

这种语法将模块pizza中的每个函数都复制到这个程序文件当中,由于导入了每个函数,可通过名称来调用每个函数,无需使用点号。

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

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

函数编写指南:

①应给函数指定描述性名称,且只使用小写字母和下划线

②每个函数都应包含简要阐述其功能达到注释

③在给形参指定默认值时,等号两边不要有空格

④所有的import语句都应该放在文件开头,唯一例外是你要在文件开头使用注释来描述整个程序

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值