如何在Python中定义一个函数?

275 阅读7分钟

函数是命名的代码块,旨在完成一项特定的工作。函数允许你写一次代码,然后可以在你需要完成同样的任务时运行。函数可以接收它们需要的信息,并返回它们产生的信息。有效地使用函数可以使你的程序更容易编写、阅读、测试和修复。在本教程中,我们将学习如何定义一个函数,如何传递参数,定义参数,设置默认值,以及更多。


如何在Python中定义一个函数

要在 Python 中定义一个函数,你可以使用 def关键字。紧跟在 def关键字是函数的名称,之后是一组括号()和一个冒号:.一个函数的主体缩进一级。根据PEP 8,Python代码的风格指南,缩进的程度应该是4个空格。要调用一个函数,只需在括号后写上函数的名字即可().

定义一个Python函数

def hello_world():
    print('Hello World!')


hello_world()
Hello World!

Python函数的参数

当你调用一个函数时,你可以向它传递信息。这就是所谓的参数。在调用函数时,参数被包含在函数名称后面的括号中。当你定义一个期望接收某条信息的函数时,它被称为参数。参数在函数的定义中被列在括号里。

传递一个参数

def hello_friend(friend):
    print(f'Hello, {friend}!')


hello_friend('Mosely')
hello_friend('Winnie')
Hello, Mosely!
Hello, Winnie!

传递一个列表作为参数

如果你需要一次向一个函数传递几个值,你可以用一个列表来实现。该函数能够处理列表中的值。如果函数对列表做了任何改变,原始列表就会被修改。如果你需要保持原始列表的完整性,你可以传递一个列表的副本作为参数。

传递一个列表作为参数

def hello_friends(names):
    for name in names:
        message = f'Hello, {name}!'
        print(message)


hello_friends(['Winnie', 'Mosely', 'Bella', 'Mugsy'])
Hello, Winnie!
Hello, Mosely!
Hello, Bella!
Hello, Mugsy!

允许一个函数修改一个列表

下面显示了在函数执行过程中原始列表是如何被修改的。列表开始时有 4 个名字,但在函数运行后有 0 个名字。

def hello_friends(names):
    while names:
        name = names.pop()
        message = f'Hello, {name}!'
        print(message)


original = ['Winnie', 'Mosely', 'Bella', 'Mugsy']
print(original)
hello_friends(original)
print(original)
['Winnie', 'Mosely', 'Bella', 'Mugsy']
Hello, Mugsy!
Hello, Bella!
Hello, Mosely!
Hello, Winnie!
[]

阻止一个函数修改列表

在这个例子中,我们通过向函数传递一个原始列表的副本来确保原始列表保持不变。

def hello_friends(names):
    while names:
        name = names.pop()
        message = f'Hello, {name}!'
        print(message)


original = ['Winnie', 'Mosely', 'Bella', 'Mugsy']
copy = original[:]
print(original)
hello_friends(copy)
print(original)
['Winnie', 'Mosely', 'Bella', 'Mugsy']
Hello, Mugsy!
Hello, Bella!
Hello, Mosely!
Hello, Winnie!
['Winnie', 'Mosely', 'Bella', 'Mugsy']


位置参数和关键字参数

参数可以是位置性的,也可以是关键字性的。位置性参数只是将函数调用中的第一个参数与函数定义中的第一个参数排列在一起,以此类推。关键字参数依靠程序员来指定每个参数在函数调用中应该分配给哪个参数。对于关键字参数,顺序并不重要。

使用位置参数

def describe_car(make, model):
    print(f'The {make} {model} is a neat vehicle')


describe_car('Subaru', 'WRX')
describe_car('Tesla', 'Model 3')
describe_car('Tesla', 'Cybertruck')
The Subaru WRX is a neat vehicle
The Tesla Model 3 is a neat vehicle
The Tesla Cybertruck is a neat vehicle

使用关键字参数

def describe_car(make, model):
    print(f'The {make} {model} is a neat vehicle')


describe_car('Subaru', 'WRX')
describe_car(make='Tesla', model='Model 3')
describe_car(model='Corvette', make='Chevy')
The Subaru WRX is a neat vehicle
The Tesla Model 3 is a neat vehicle
The Chevy Corvette is a neat vehicle


默认值

如果你愿意,你可以用默认值指定一个参数。这样,当函数被调用时,如果没有提供参数,将使用默认值。有默认值的参数必须列在函数定义中没有默认值的参数之后,以确保位置参数仍然有效。

使用缺省值

def describe_car(make, model='WRX'):
    print(f'The {make} {model} is a neat vehicle')


describe_car('Subaru')
The Subaru WRX is a neat vehicle

使用None使一个参数成为可选参数

def describe_car(make, model=None):
    if model:
        print(f'The {make} {model} is a neat vehicle')
    else:
        print(f'The {make} is a neat vehicle')


describe_car('Subaru')
describe_car(model='Corvette', make='Chevy')
The Subaru is a neat vehicle
The Chevy Corvette is a neat vehicle


传递任意数量的参数

如果你不知道一个函数被调用时需要多少个参数,那么你可以使用星号 *****操作符来收集任意数量的参数。一个接受可变参数数的参数必须在函数定义中最后出现。如果你想用关键字参数来做这个,那么可以使用双星号 ******操作符。这些参数被存储为一个字典,参数名是键,参数是值。

具有任意数量参数的函数

def make_a_sandwich(type, *veggies):
    print(f'nMaking a {type} Sandwich.')
    print('It has these veggies:')
    for veggie in veggies:
        print(f'- {veggie}')


make_a_sandwich('Ham', 'Onions')
make_a_sandwich('Roast Beef', 'Lettuce', 'Tomato')
make_a_sandwich('Turkey', 'Lettuce', 'Tomato', 'Peppers')
Making a Ham Sandwich.
It has these veggies:
- Onions

Making a Roast Beef Sandwich.
It has these veggies:
- Lettuce
- Tomato

Making a Turkey Sandwich.
It has these veggies:
- Lettuce
- Tomato
- Peppers

收集任意数量的关键字参数

def make_a_sandwich(type, **veggies):
    print(f'nMaking a {type} Sandwich.')
    print('It has these veggies:')
    for veggie in veggies:
        print(f'- {veggies[veggie]}')


make_a_sandwich('Ham', one='Onions')
make_a_sandwich('Roast Beef', one='Onions', two='Peppers')
make_a_sandwich('Turkey', one='Olives', two='Spinach', three='Cucumbers')
Making a Ham Sandwich.
It has these veggies:
- Onions

Making a Roast Beef Sandwich.
It has these veggies:
- Onions
- Peppers

Making a Turkey Sandwich.
It has these veggies:
- Olives
- Spinach
- Cucumbers


如何构造一个函数

到目前为止,我们已经看到了一些编写和调用函数的方法。如果你想知道什么是结构化代码的最佳方式,只需尝试得到一些能用的东西。这就是主要的目标!随着经验的增加,你会发展出一种感觉,使不同的结构,如位置参数和关键字参数更具优势。只要你的函数在做你想做的工作,那就很好。


返回值

函数所做的一项常见工作是返回一个值。换句话说,你希望能够给一个函数一些数据,让它给你一些其他的数据或值。为了从一个函数中获取返回值,调用行应该提供一个变量,返回值可以被分配给这个变量。一旦函数到达一个返回语句,它就停止运行。

返回一个单一的值

def get_full_name(first, last):
    full_name = f'{first} {last}'
    return full_name.title()


comedian = get_full_name('ricky', 'gervais')
print(comedian)
Ricky Gervais

返回一个字典

def build_house(type, bedrooms):
    house = {'type': type, 'bedrooms': bedrooms}
    return house


house = build_house('Colonial', 3)
print(house)
{'type': 'Colonial', 'bedrooms': 3}

返回一个带有可选值的字典

def build_house(type, bedrooms, pool=None):
    house = {'type': type, 'bedrooms': bedrooms}
    if pool:
        house['pool'] = pool
    return house


house = build_house('Colonial', 3)
print(house)

house = build_house('Colonial', 2, 'No')
print(house)
{'type': 'Colonial', 'bedrooms': 3}
{'type': 'Colonial', 'bedrooms': 2, 'pool': 'No'}


模块

在 Python 中,函数可以存储在一个单独的文件中,然后在需要时导入。这就是所谓的 "模块"。模块使程序文件更加简洁。当使用一个模块时,你希望将模块文件与主程序存放在同一目录下。

将一个函数存储在一个模块中

sandwichmaker.py

def make_a_sandwich(type, *veggies):
    print(f'nMaking a {type} Sandwich.')
    print('It has these veggies:')
    for veggie in veggies:
        print(f'- {veggie}')

导入整个模块

functions.py
模块中的每个函数都可以在程序文件中使用。

import sandwichmaker

sandwichmaker.make_a_sandwich('Pastrami', 'Lettuce', 'Tomato')
sandwichmaker.make_a_sandwich('Corned Beef', 'Pickles', 'Jalapenos')
Making a Pastrami Sandwich.
It has these veggies:
- Lettuce
- Tomato

Making a Corned Beef Sandwich.
It has these veggies:
- Pickles
- Jalapenos

导入一个特定的函数

只有导入的函数在程序文件中是可用的。

from sandwichmaker import make_a_sandwich

make_a_sandwich('Egg', 'Lettuce', 'Tomato')
make_a_sandwich('Steak', 'Pickles', 'Relish')
Making a Egg Sandwich.
It has these veggies:
- Lettuce
- Tomato

Making a Steak Sandwich.
It has these veggies:
- Pickles
- Relish

给予一个模块一个别名

import sandwichmaker as s

s.make_a_sandwich('Honey Ham', 'Spinach', 'Tomato')
s.make_a_sandwich('Angus Roast Beef', 'Avacado', 'Sun Dried Tomato')
Making a Honey Ham Sandwich.
It has these veggies:
- Spinach
- Tomato

Making a Angus Roast Beef Sandwich.
It has these veggies:
- Avacado
- Sun Dried Tomato

给一个函数一个别名

from sandwichmaker import make_a_sandwich as mas

mas('Honey Ham', 'Spinach', 'Tomato')
mas('Angus Roast Beef', 'Avacado', 'Sun Dried Tomato')

从一个模块中导入所有函数

使用通配符导入所有函数是可能的,但这可能导致命名冲突,从而引起错误。最好是避免这种做法

from sandwichmaker import *

make_a_sandwich('Honey Ham', 'Spinach', 'Tomato')
make_a_sandwich('Angus Roast Beef', 'Avacado', 'Sun Dried Tomato')

Python函数教程总结

所有的编程语言都允许你将一连串的指令捆绑起来,以便在你认为合适的时候重新使用。Python也不例外,而且还提供了通过利用这些可重复使用的功能片段来简化程序的能力。一个函数只是一段代码,用来完成一个特定的任务。函数可以利用传入的数据,并可以返回各种类型的数据,尽管它们并不要求这样做。