Python 函数基础

PythonBeginner
立即练习

介绍

在本实验中,你将学习如何定义和使用 Python 函数。我们将从简单的示例开始,逐步增加复杂度。

让我们开始吧!

学习目标

  • Python 函数

定义 Python 函数

要定义一个 Python 函数,你需要使用 def 关键字,后跟函数名和一组可能包含参数的括号。函数体缩进并跟在 : 字符之后。

打开一个新的 Python 解释器。

python3

以下是一个简单的函数示例,它接受一个参数 x 并返回 x 的平方:

def square(x):
  return x ** 2

在这个示例中,square 函数接受一个参数 x 并返回 x 的平方。使用 return 语句将值返回给调用者。

要调用函数,只需使用函数名后跟一组括号和必要的参数。例如:

result = square(5)  ## result 是 25
print(result)

如果函数没有 return 语句,它将默认返回 None。例如:

def square(x):
  print(x ** 2)

result = square(5)  ## result 是 None
print(result)

你必须了解 returnprint 语句的区别。print 语句用于在屏幕上打印值,而 return 语句用于从函数返回值。

也可以使用 return 语句提前结束函数的执行。例如:

def find_first_positive(numbers):
  for number in numbers:
    if number > 0:
      return number
  return None

result = find_first_positive([-1, -2, 3, -4, 5])  ## result 是 3
print(result)

在这个示例中,find_first_positive 函数返回 numbers 列表中的第一个正数,如果没有找到正数则返回 Nonereturn 语句在找到正数后立即结束函数的执行。

函数参数

有时,为函数参数指定默认值非常有用。这样,调用函数时可以不传递该参数的值,而是使用默认值。

以下是一个计算矩形面积的函数示例。它接受两个参数:矩形的长度和宽度。我们可以为这两个参数指定默认值,以便在长度和宽度相等时,只需传递一个参数即可调用函数:

def rectangle_area(length, width=1):
  return length * width

print(rectangle_area(5))  ## 输出:5
print(rectangle_area(5, 2))  ## 输出:10

在这个示例中,width 参数的默认值为 1。如果调用函数时只传递一个参数,则 width 将使用默认值 1。

自己试试:定义一个名为 power 的函数,它接受两个参数:基数 x 和指数 n。将指数参数设为可选,默认值为 2。然后使用不同的基数和指数值调用该函数。

def power(x, n=2):
  return x ** n

print(power(2))  ## 输出:4
print(power(2, 3))  ## 输出:8

参数类型提示

在 Python 中,函数参数类型提示用于指示传递给函数的参数的预期类型。它们是在 Python 3.5 中引入的,通过在函数定义中的参数名称后加上冒号和类型来表示。

类型提示是可选的,不会影响代码的运行时行为。它们主要用于 IDE 和 Linter 等工具,以提供更好的代码分析和自动补全建议。

例如,考虑以下函数,它接受两个参数:一个整数和一个字符串,并返回它们的连接结果:

def concatenate(a: int, b: str) -> str:
    return str(a) + b

print(concatenate(1, "world")) ## "1world"

在这个示例中,类型提示 intstr 表示第一个参数 a 应为整数,第二个参数 b 应为字符串。

类型提示也可以与类及其实例一起使用,例如:

class MyClass:
    pass

def my_function(a: MyClass) -> None:
    pass

值得一提的是,类型提示是可选的,不会影响代码的运行时行为。它们主要用于 IDE 和 Linter 等工具,以提供更好的代码分析和自动补全建议。

此外,Python 有一个名为 typing 的模块,其中包含 ListTupleDictSet 等有用的类型,可用于提示集合中元素的类型。

from typing import List, Tuple
def my_function(a: List[int], b: Tuple[str, int]) -> None:
    pass

在代码中使用类型提示是一种良好的实践,可以使代码更具可读性和可维护性。

文档字符串(Docstring)

文档字符串是出现在模块、函数、类或方法定义中的第一个语句的字符串字面量。这样的文档字符串会成为该对象的 __doc__ 特殊属性。

文档字符串用于记录代码,通常以纯文本形式编写。它们用三重引号 """ 括起来,通常放在函数定义的开头。

def my_function():
    """这是一个文档字符串。"""
    pass

文档字符串通常包含函数的简短描述、参数及其返回值。它们还可以包含函数行为的详细描述。

def my_function(a: int, b: int) -> int:
    """返回 a 和 b 的和。

    参数:
        a (int): 第一个数字。
        b (int): 第二个数字。

    返回值:
        int: a 和 b 的和。
    """
    return a + b

返回多个值

在 Python 中,函数可以使用元组返回多个值。以下是一个计算列表最小值和最大值的函数示例:

def min_max(numbers):
  return min(numbers), max(numbers)

nums = [1, 2, 3, 4, 5]
min_val, max_val = min_max(nums)
print("Minimum value:", min_val)  ## 输出:"Minimum value: 1"
print("Maximum value:", max_val)  ## 输出:"Maximum value: 5"

在这个示例中,min_max 函数返回一个包含 numbers 列表最小值和最大值的元组。调用函数时,元组会被解包到变量 min_valmax_val 中。

以下是另一个从函数返回多个值的示例:

def get_student_info(name):
  if name == "John":
    return "John", "Doe", "Computer Science"
  elif name == "Jane":
    return "Jane", "Smith", "Physics"
  else:
    return "Unknown", "Unknown", "Unknown"

first_name, last_name, major = get_student_info("John")
print("First name:", first_name)  ## 输出:"First name: John"
print("Last name:", last_name)  ## 输出:"Last name: Doe"
print("Major:", major)  ## 输出:"Major: Computer Science"

first_name, last_name, major = get_student_info("Jane")
print("First name:", first_name)  ## 输出:"First name: Jane"
print("Last name:", last_name)  ## 输出:"Last name: Smith"
print("Major:", major)  ## 输出:"Major: Physics"

first_name, last_name, major = get_student_info("Bob")
print("First name:", first_name)  ## 输出:"First name: Unknown"
print("Last name:", last_name)  ## 输出:"Last name: Unknown"
print("Major:", major)  ## 输出:"Major: Unknown"

在这个示例中,get_student_info 函数接受一个学生姓名,并返回一个包含学生名字、姓氏和专业的元组。调用函数时,元组会被解包到单独的变量中。

如果学生姓名未被识别,函数将返回一个包含 "Unknown" 值的元组。

关键字参数

在 Python 中,你可以使用“关键字参数”来指定函数参数。当你使用关键字参数时,你需要指定参数名称后跟值,并且参数可以以任意顺序提供。

以下是一个接受两个参数的函数示例:namemessage

def greet(name, message):
  print("Hello, " + name + "! " + message)

greet(message="How are you?", name="John")  ## 输出:"Hello, John! How are you?"

在这个示例中,greet 函数被调用时传递了参数 "John" 和 "How are you?",但参数的顺序与函数定义中的顺序不同。通过使用关键字参数,你可以以任意顺序指定参数,使代码更具可读性。

你也可以混合使用关键字参数和位置参数,只要位置参数在前面提供即可。例如:

def greet(name, message):
  print("Hello, " + name + "! " + message)

greet("John", message="How are you?")  ## 输出:"Hello, John! How are you?"

在这个示例中,name 参数作为位置参数提供,而 message 参数作为关键字参数提供。

关键字参数在函数有大量参数或参数具有默认值时特别有用。例如:

def create_user(name, age=18, gender="unknown"):
  print("Creating user:", name, age, gender)

create_user("John")  ## 输出:"Creating user: John 18 unknown"
create_user("Jane", gender="female")  ## 输出:"Creating user: Jane 18 female"
create_user("Bob", 25, "male")  ## 输出:"Creating user: Bob 25 male"

在这个示例中,create_user 函数接受三个参数:nameagegenderagegender 参数具有默认值,因此它们是可选的。通过使用关键字参数,你可以仅指定你想要提供的参数,其余参数将使用默认值。

Args 和 Kwargs

在 Python 中,你可以使用 *args**kwargs 语法来定义一个可以接受可变数量参数的函数。

*args 语法用于向函数传递可变数量的非关键字参数。例如:

def print_numbers(*args):
  for arg in args:
    print(arg)

print_numbers(1, 2, 3, 4, 5)  ## 输出:1, 2, 3, 4, 5
print_numbers(10, 20, 30)  ## 输出:10, 20, 30

在这个示例中,print_numbers 函数接受可变数量的参数并将它们打印到控制台。*args 语法用于定义函数,参数以元组的形式传递给函数。

**kwargs 语法用于向函数传递可变数量的关键字参数。例如:

def print_keywords(**kwargs):
  for key, value in kwargs.items():
    print(key, ":", value)

print_keywords(name="John", age=30, city="New York")
## 输出:
## name : John
## age : 30
## city : New York

print_keywords(country="USA", population=327000000)
## 输出:
## country : USA
## population : 327000000

在这个示例中,print_keywords 函数接受可变数量的关键字参数并将它们打印到控制台。**kwargs 语法用于定义函数,参数以字典的形式传递给函数。

你可以在函数定义中将 *args**kwargs 语法与其他参数混合使用,只要 *args**kwargs 参数放在最后即可。例如:

def print_info(title, *args, **kwargs):
  print(title)
  for arg in args:
    print(arg)
  for key, value in kwargs.items():
    print(key, ":", value)

print_info("Person", "John", "Jane", "Bob", age=30, city="New York")
## 输出:
## Person
## John
## Jane
## Bob
## age : 30
## city : New York

在这个示例中,print_info 函数接受一个固定参数 title,后跟可变数量的非关键字参数(*args)和可变数量的关键字参数(**kwargs)。参数按照定义的顺序传递给函数:首先是 title,然后是 *args,最后是 **kwargs

*args**kwargs 语法在你想要定义一个可以接受可变数量参数的灵活函数时非常有用。它们还可以通过避免在函数定义中使用硬编码的参数名称来提高代码的可读性。

以下是一个使用 *args**kwargs 创建参数字典的函数示例:

def create_dict(**kwargs):
  return kwargs

my_dict = create_dict(name="John", age=30, city="New York")
print(my_dict)  ## 输出:{'name': 'John', 'age': 30, 'city': 'New York'}

my_dict = create_dict(a=1, b=2, c=3)
print(my_dict)  ## 输出:{'a': 1, 'b': 2, 'c': 3}

在这个示例中,create_dict 函数接受可变数量的关键字参数并将它们作为字典返回。**kwargs 语法用于定义函数,参数以字典的形式传递给函数。

你还可以使用 * 运算符在调用函数时将列表或元组“解包”为单独的参数。例如:

def print_numbers(*args):
  for arg in args:
    print(arg)

numbers = [1, 2, 3, 4, 5]
print_numbers(*numbers)  ## 输出:1, 2, 3, 4, 5

tuple_of_numbers = (10, 20, 30)
print_numbers(*tuple_of_numbers)  ## 输出:10, 20, 30

在这个示例中,* 运算符用于在调用 print_numbers 函数时将 numbers 列表和 tuple_of_numbers 元组解包为单独的参数。

你还可以使用 ** 运算符在调用函数时将字典解包为关键字参数。例如:

def print_keywords(**kwargs):
  for key, value in kwargs.items():
    print(key, ":", value)

my_dict = {'name': 'John', 'age': 30, 'city': 'New York'}
print_keywords(**my_dict)
## 输出:
## name : John
## age : 30
## city : New York

another_dict = {'country': 'USA', 'population': 327000000}
print_keywords(**another_dict)
## 输出:
## country : USA
## population : 327000000

在这个示例中,** 运算符用于在调用 print_keywords 函数时将 my_dictanother_dict 字典解包为关键字参数。

Lambda 函数

在 Python 中,你可以使用“lambda 函数”来创建匿名函数。Lambda 函数是没有名称的小型函数,通常在一行代码中定义和调用。

以下是一个接受两个参数并返回它们之和的 lambda 函数示例:

sum = lambda x, y: x + y

result = sum(1, 2)  ## result is 3

在这个示例中,lambda 关键字用于定义一个接受两个参数 xy 并返回它们之和的 lambda 函数。该 lambda 函数被赋值给 sum 变量,并且可以像其他函数一样调用。

你可以使用普通函数代替 lambda 函数来定义相同的函数吗?

def sum(x, y):
  return x + y

result = sum(1, 2)  ## result is 3

Lambda 函数通常用作定义简单函数的快捷方式。当你想要将函数作为参数传递给另一个函数,或者想要内联定义函数时,它们特别有用。

以下是将 lambda 函数作为 sorted 函数的参数使用的示例:

words = ["apple", "banana", "cherry", "date"]
sorted_words = sorted(words, key=lambda x: len(x))
print(sorted_words)  ## 输出:['apple', 'date', 'banana', 'cherry']

在这个示例中,sorted 函数接受一个单词列表和一个指定如何排序的“key”函数。作为 key 函数传递的 lambda 函数返回每个单词的长度,单词根据它们的长度进行排序。

以下是一个内联定义 lambda 函数的示例:

result = (lambda x: x ** 2)(5)  ## result is 25

在这个示例中,lambda 函数接受一个参数 x 并返回 x 的平方。lambda 函数在一行代码中定义并调用,结果被赋值给 result 变量。

Lambda 函数通常用于 Python 中不需要在代码其他地方重用的简短、简单的函数。它们是一种方便的方式,可以在不定义单独函数的情况下快速定义小型函数,而无需使用 def 关键字。

局部作用域与全局作用域

在 Python 中,函数内部定义的变量是“局部”变量,只能在函数内部访问。函数外部定义的变量是“全局”变量,可以在整个程序中访问。

以下是一个全局变量的示例:

message = "Hello, world!"

def greet():
  print(message)

greet()  ## 输出:"Hello, world!"

在这个示例中,message 变量定义在 greet 函数外部,因此它是一个全局变量。greet 函数可以访问并打印 message 变量,因为它在整个程序中都是可用的。

以下是一个局部变量的示例:

def greet(name):
  message = "Hello, " + name + "!"
  print(message)

greet("John")  ## 输出:"Hello, John!"
print(message)  ## 输出:NameError: name 'message' is not defined

在这个示例中,message 变量定义在 greet 函数内部,因此它是一个局部变量。greet 函数可以访问并打印 message 变量,但它在函数外部不可用。如果你尝试在函数外部访问 message 变量,你会得到一个 NameError,因为该变量未定义。

你也可以使用 global 关键字在函数内部修改全局变量。例如:

message = "Hello, world!"

def greet():
  global message
  message = "Hello, Python!"
  print(message)

greet()  ## 输出:"Hello, Python!"
print(message)  ## 输出:"Hello, Python!"

在这个示例中,greet 函数使用 global 关键字修改了全局变量 messagegreet 函数打印了修改后的 message 值,并且 message 的值在函数外部也被修改了。

通常建议避免使用全局变量,因为它们会使代码更难理解和维护。通常更好的做法是将变量作为参数传递给函数,并将它们作为结果返回,而不是修改全局变量。

将函数作为另一个函数的参数

在 Python 中,你可以将一个函数作为参数传递给另一个函数。这被称为“高阶函数”。以下是一个接受另一个函数作为参数并多次调用它的函数示例:

def greet(name):
  print("Hello, " + name + "!")

def call(func, args):
  for arg in args:
    func(arg)

names = ["John", "Jane", "Bob"]
call(greet, names)  ## 输出:"Hello, John!", "Hello, Jane!", "Hello, Bob!"

在这个示例中,call 函数接受两个参数:一个函数 func 和一个参数列表 args。它使用 args 列表中的每个元素作为参数调用 func 函数。

自己试试:定义一个名为 apply 的函数,它接受一个函数和一个数字列表,并返回一个新列表,其中包含将函数应用于列表中每个元素的结果。

def square(x):
  return x ** 2

def apply(func, numbers):
  result = []
  for number in numbers:
    result.append(func(number))
  return result

numbers = [1, 2, 3, 4, 5]
squared_numbers = apply(square, numbers)
print(squared_numbers)  ## 输出:[1, 4, 9, 16, 25]

这一步可能有点难,如果你无法解决也不要担心。你可以跳过它,稍后再回来尝试。

总结

你现在应该对如何使用 Python 函数有了很好的理解。以下是一些关键点:

  1. Python 函数是可以定义、调用和重用的代码块。
  2. 你可以使用 def 关键字定义函数,后跟函数名称和参数。
  3. 函数体应该缩进,你可以使用 return 关键字从函数中返回值。
  4. 你可以使用“关键字参数”来指定函数参数,这允许你在调用函数时指定参数名称和值。
  5. 你可以使用 *args 语法定义一个可以接受可变数量非关键字参数的函数,使用 **kwargs 语法定义一个可以接受可变数量关键字参数的函数。
  6. 你可以使用 lambda 关键字创建匿名函数,这些函数在一行代码中定义和调用。
  7. 在 Python 中,函数内部定义的变量是局部变量,只能在函数内部访问。函数外部定义的变量是全局变量,可以在整个程序中访问。
  8. 通常建议避免使用全局变量,而是将变量作为参数传递给函数,并将它们作为结果返回。