【python基础】函数详解:编写函数、传递参数、使用位置实参、函数存储到模块中、函数编写指南

文章目录

  • 一. 函数定义语法
  • 二. 向函数传参
    • 1. 参数传参
    • 2. 关键字实参
    • 3. 参数默认值
    • 4. 等效的函数调用
  • 三. 返回值
    • 1. 返回简单值
    • 2. 让实参变成可选的
    • 3. 返回字典
    • 4. 结合使用函数和while循环
  • 四. 传递列表
    • 1. 在函数中修改列表
    • 2. 禁止函数修改列表
  • 五. 传递任意数量的实参
    • 1. 结合使用位置实参和任意数量实参
    • 2. 使用任意数量的关键字实参
  • 六. 将函数存储在模块中
    • 1. 导入整个模块
    • 2. 导入特定的函数
    • 3. 使用as给函数指定别名
    • 4. 使用as给模块指定别名
    • 5. 导入模块中的所有函数(不推荐)
  • 七. 函数编写指南

本文将学到:

  • 如何编写函数,以及如何传递实参,让函数能够访问完成其工作所需的信息;
  • 如何使用位置实参和关键字实参,以及如何接受任意数量的实参;显示输出的函数和返回值的函数;
  • 如何将函数同列表、字典、if语句和while循环结合起来使用;
  • 如何将函数存储在称为模块的独立文件中,让程序文件更简单、更易于理解。
  • 函数编写指南,遵循这些指南可让程序始终结构良好,并对你和其他人来说易于阅读。

一. 函数定义语法

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

❹ greet_user()

函数定义

❶处的代码行使用关键字def来告诉Python,你要定义一个函数。后面指定了函数名,圆括号里指定参数,这里没有参数。最后,定义以冒号结尾。

函数体

  • 在def greet_user():后面的所有缩进行构成了函数体
  • ❷处的文本是称为文档字符串(docstring)的注释,描述了函数是做什么的。文档字符串用三引号括起。

调用函数

要调用函数,可依次指定函数名以及用圆括号括起的必要信息,如❹处所示。

def greet_user():
    """你好这是一个注释文档"""
    print("hello")


if __name__ == '__main__':
    greet_user()

 

二. 向函数传参

1. 参数传参

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


if __name__ == '__main__':
    greet_user2('jesse')

 

2. 关键字实参

关键字实参是传递给函数的名称值对。关键字实参让你无须考虑函数调用中的实参顺序,还清楚地指出了函数调用中各个值的用途。

def describe_pet(animal_type, pet_name):
    """显示宠物的信息。"""
    print(f"\nI have a {animal_type}.")
    print(f"My {animal_type}'s name is {pet_name.title()}.")

if __name__ == '__main__':
    describe_pet(animal_type='hamster', pet_name='harry')

关键字实参的顺序无关紧要,因为Python知道各个值该赋给哪个形参。下面两个函数调用是等效的:

describe_pet(animal_type='hamster', pet_name='harry')
describe_pet(pet_name='harry', animal_type='hamster')

3. 参数默认值

编写函数时,可给每个形参指定默认值。

如果你发现调用describe_pet()时,描述的大多是小狗,就可将形参animal_type的默认值设置为’dog’。这样,调用describe_pet()来描述小狗时,就可不提供这种信息:

def describe_pet(pet_name, animal_type='dog'):
    """显示宠物的信息。"""
    print(f"\nI have a {animal_type}.")
    print(f"My {animal_type}'s name is {pet_name.title()}.")

if __name__ == '__main__':
    describe_pet(pet_name='willie')

# I have a dog.
# My dog's name is Willie.

虽然给animal_type指定了默认值,但py依然将这个参数视为位置参数。所以如果函数调用中只包含宠物的名字,这个实参将关联到函数定义的形参。所以这就是需要将pet_name放在形参列表开头的原因。

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

describe_pet('willie')

 

4. 等效的函数调用

# 一条名为Willie的小狗。
describe_pet('willie')
describe_pet(pet_name='willie')

# 一只名为Harry的仓鼠。
describe_pet('harry', 'hamster')
describe_pet(pet_name='harry', animal_type='hamster')
describe_pet(animal_type='hamster', pet_name='harry')

 

三. 返回值

函数返回的值称为返回值。在函数中,可使用return语句将值返回到调用函数的代码行,从而简化主程序。

1. 返回简单值

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

if __name__ == '__main__':
    musician = get_formatted_name('roman', 'gao')
    print(musician)

调用返回值的函数时,需要提供一个变量,以便将返回的值赋给它。

 

2. 让实参变成可选的

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()


if __name__ == '__main__':
    musician = get_formatted_name('jimi', 'hendrix')
    print(musician)

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

# Jimi Hendrix
# John Lee Hooker

 

3. 返回字典

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


if __name__ == '__main__':
    musician = build_person('jimi', 'hendrix')
    print(musician)

 

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

if __name__ == '__main__':
    musician = build_person('jimi', 'hendrix', age=27)
    print(musician)

在函数定义中,新增了一个可选形参age,并将其默认值设置为特殊值None(表示变量没有值)。如果函数调用中包含形参age的值,这个值将被存储到字典中。

可将None视为占位值。在条件测试中,None相当于False。

 

4. 结合使用函数和while循环

def get_formatted_name(first_name, last_name):
    """返回整洁的姓名。"""
    full_name = f"{first_name} {last_name}"
    return full_name.title()

if __name__ == '__main__':
    # 这是一个无限循环
    while True:
        print("\nPlease tell me your name:")
        f_name = input("First name: ")
        l_name = input("Last name: ")

        formatted_name = get_formatted_name(f_name, l_name)
        print(f"\nHello, {formatted_name}!")

 

四. 传递列表

def greet_users(names):
    """向列表中的每位用户发出简单的问候。"""
    for name in names:
        msg = f"Hello, {name.title()}!"
        print(msg)


if __name__ == '__main__':
    usernames = ['hannah', 'ty', 'margot']
    greet_users(usernames)

 

1. 在函数中修改列表

def print_models(unprinted_designs, completed_models):
    """
    模拟打印每个设计,直到没有未打印的设计为止。
    打印每个设计后,都将其移到列表completed_models中。
    """
    while unprinted_designs:
        current_design = unprinted_designs.pop()
        print(f"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)


if __name__ == '__main__':
    unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
    completed_models = []

    print_models(unprinted_designs, completed_models)
    show_completed_models(completed_models)

 

2. 禁止函数修改列表

有时候,需要禁止函数修改列表。可向函数传递列表的副本而非原件。这样,函数所做的任何修改都只影响副本,而原件丝毫不受影响。

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

function_name(list_name_[:])

切片表示法[:]创建列表的副本。
 

如果不想清空未打印的设计列表,可像下面这样调用print_models():

print_models(unprinted_designs[:], completed_models)

 

五. 传递任意数量的实参

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

def make_pizza(*toppings):
    """打印顾客点的所有配料。"""
    print(toppings)


if __name__ == '__main__':
    make_pizza('pepperoni')
    make

 

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

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

def make_pizza(size, *toppings):
    """概述要制作的比萨。"""
    print(f"\nMaking a {size}-inch pizza with the following toppings:")
    for topping in toppings:
        print(f"- {topping}")


if __name__ == '__main__':
    make_pizza(16, 'pepperoni')
    make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

注意:你经常会看到通用形参名*args,它也收集任意数量的位置实参。
 

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

def build_profile(first, last, **user_info):
    """创建一个字典,其中包含我们知道的有关用户的一切。"""
    user_info['first_name'] = first
    user_info['last_name'] = last
    return user_info



if __name__ == '__main__':
    user_profile = build_profile('albert', 'einstein',
                                 location='princeton',
                                 field='physics')
    print(user_profile)

# {'location': 'princeton', 'field': 'physics', 'first_name': 'albert', 'last_name': 'einstein'}

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

 

六. 将函数存储在模块中

语法

  • 可以将函数存储在称为模块的独立文件中,再将模块导入到主程序中。
  • import语句允许在当前运行的程序文件中使用模块中的代码。

作用

  • 通过将函数存储在独立的文件中,可隐藏程序代码的细节,将重点放在程序的高层逻辑上。
  • 这还能让你在众多不同的程序中重用函数。
  • 将函数存储在独立文件中后,可与其他程序员共享这些文件而不是整个程序。
  • 使用其他程序员编写的函数库。

1. 导入整个模块

要让函数是可导入的,得先创建模块。模块是扩展名为.py的文件,包含要导入到程序中的代码。

下面来创建一个包含函数make_pizza()的模块: pizza.py

def make_pizza(size, *toppings):
    """概述要制作的比萨。"""
    print(f"\nMaking a {size}-inch pizza with the following toppings:")
    for topping in toppings:
        print(f"- {topping}")

创建调用making_pizzas.py文件

只需编写一条import语句并在其中指定模块名,就可在程序中使用该模块中的所有函数。

import pizza

if __name__ == '__main__':
    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语句导入了名为module_name.py的整个模块,就可使用下面的语法来使用其中任何一个函数:

module_name.function_name()

 

2. 导入特定的函数

还可以导入模块中的特定函数,这种导入方法的语法如下:

from module_name import function_name

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

from module_name import function_0, function_1, function_2

对于前面的making_pizzas.py示例,如果只想导入要使用的函数,代码将类似于下面这样:

from pizza import make_pizza

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

 

3. 使用as给函数指定别名

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

 
下面给函数make_pizza()指定了别名mp()。

这是在import语句中使用make_pizza as mp实现的,关键字as将函数重命名为指定的别名

from pizza import make_pizza as mp

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

指定别名通用语法:

from module_name import function_name as fn

 

4. 使用as给模块指定别名

import pizza as p

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

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

import module_name as mn

 

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

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

from pizza import *

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

由于导入了每个函数,可通过名称来调用每个函数,而无须使用句点表示法。

但注意:使用并非自己编写的大型模块时,最好不要采用这种导入方法。

这是因为如果模块中有函数的名称与当前项目中使用的名称相同,可能导致意想不到的结果:Python可能遇到多个名称相同的函数或变量,进而覆盖函数,而不是分别导入所有的函数。

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

 

七. 函数编写指南

编写函数时,需要牢记几个细节。

  1. 应给函数指定描述性名称,且只在其中使用小写字母和下划线。给模块命名时也应遵循上述约定。

  2. 每个函数都应包含简要地阐述其功能的注释。该注释应紧跟在函数定义后面,并采用文档字符串格式。文档良好的函数让其他程序员只需阅读文档字符串中的描述就能够使用它。

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

    def function_name(parameter_0, parameter_1='default value')
    

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

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

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

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

    def function_name(
            parameter_0, parameter_1, parameter_2,
            parameter_3, parameter_4, parameter_5):
    function body...
    

 

参考:《Python编程:从入门到实战(第二版)》

你可能感兴趣的:(python,python,开发语言)