Funtion

1. Why function?

  1. 减少重复,容易维护和理解,复用性
  2. 模块化

Examples

  • main()
  • print()
  • abs()
  • math.sqrt()

2. How?

2.1 Create (define)

def drawBar(a,b):
	some 语句...
def <name>(<formal-parameters>):
	<body>

def define

drawBar identifier

(a,b) Formal-parameters

’:’ sytax

some 语句 Function body

2.2 Use (call)

drawBar(1,4)
<name>(<actual parameters>)

2.3 Local or Global (变量的作用域)

The scope of variable: namespaces 命名空间(namespace)包括三种:

  1. Build-in namespace
  2. Global namespace
  3. Local namespace 在函数内部定义的变量被称为局部变量 (Local Variable),它们只能在该函数内部访问。在函数外部定义的变量被称为全局变量 (Global Variable),它们可以在程序的任何地方访问,包括函数内部。
x = 10  # 全局变量
 
def my_function():
    y = 5  # 局部变量
    print("函数内部:", x) # 可以访问全局变量 x
    print("函数内部:", y) # 可以访问局部变量 y
 
my_function()
print("函数外部:", x) # 可以访问全局变量 x
# print("函数外部:", y) # 报错!无法访问局部变量 y

如果在函数内部尝试修改一个全局变量,并且函数内部没有定义同名的局部变量,那么会直接修改全局变量的值。但是如果在函数内部定义了一个同名的局部变量,那么对该变量的修改只会在函数内部生效,不会影响全局变量。

x = 10
 
def modify_global():
    global x  # 声明要修改全局变量 x
    x = 20
    print("函数内部修改后:", x)
 
modify_global()
print("函数外部修改后:", x)
x = 10
 
def shadow_global():
    x = 20  # 定义了一个局部变量 x,屏蔽了全局变量 x
    print("函数内部:", x)
 
shadow_global()
print("函数外部:", x)

2.4 参数传递 (Parameter Passing)

位置参数 (Positional Arguments)

按照参数定义的顺序进行传递。

def greet(name, greeting):
    print(f"{greeting}, {name}!")
 
greet("Alice", "Hello")  # 位置参数

关键字参数 (Keyword Arguments)

通过参数名来传递参数,可以不按照参数定义的顺序。

def greet(name, greeting):
    print(f"{greeting}, {name}!")
 
greet(greeting="Hi", name="Bob")  # 关键字参数

默认参数 (Default Arguments)

在函数定义时,可以为参数设置默认值。如果调用函数时没有传递该参数,则使用默认值。带有默认值的参数必须在末尾!

def greet(name, greeting="Hello"):
    print(f"{greeting}, {name}!")
 
greet("Charlie")  # 使用默认参数 greeting="Hello"
greet("David", "Good morning")  # 覆盖默认参数

可变参数 (Variable Arguments)

同样的,可变参数必须在末尾!

*args: 接收任意数量的位置参数,并将它们打包成一个元组 (tuple)。

def print_args(*args):
    for arg in args:
        print(arg)
print_args(1, 2, 3, "a", "b")

**kwargs: 接收任意数量的关键字参数,并将它们打包成一个字典 (dictionary)。

def print_kwargs(**kwargs):
	for key, value in kwargs.items():
		print(f"{key}: {value}")
print_kwargs(name="Eve", age=30, city="New York")

2.5 返回值 (Return Value)

函数可以使用 return 语句返回一个值。如果没有 return 语句,或者 return 语句后面没有表达式,则函数返回 None

def add(a, b):
    return a + b
 
result = add(3, 5)
print(result)

函数可以返回多个值,实际上是返回一个元组。

def calculate(a, b):
	sum = a + b
	difference = a - b
	return sum, difference
 
result = calculate(10, 4)
print(result)  # 输出 (14, 6)
 
sum_result, diff_result = calculate(10, 4)
print(sum_result)  # 输出 14
print(diff_result) # 输出 6

2.6 不同数据类型是否需要使用return的问题

有些数据类型是不可变的,有些是可变的,要考虑是否需要return

def func(num):
	num = num * 2
a = 1000
func(a)
print(a)
# 输出1000
def func(nums):
	for i in range(len(nums)):
		nums[i] = nums[i] * 2
a = [1000,100]
func(a)
print(a)
# 输出[2000,200]

还有一个例子:

def squareEach(nums):
    '''
    对列表中的每个元素求平方
    '''
    for i in range(len(nums)):
        nums[i] = nums[i] ** 2
    '''
    错误写法:
    for num in nums:
        num = num ** 2
    '''

2.7 递归 (Recursion)

递归是指函数调用自身。递归函数必须有一个或多个基本情况 (Base Case),用于停止递归调用,否则会导致无限循环。

def factorial(n):
    if n == 0:  # 基本情况
        return 1
    else:
        return n * factorial(n - 1)  # 递归调用
 
print(factorial(5))

数学公式: 阶乘的定义:


2.8 匿名函数 (Lambda Functions)

匿名函数是一种没有名字的函数,通常用于简单的函数定义。使用 lambda 关键字创建。

square = lambda x: x * x
print(square(5))
 
print((lambda x: x * x)(5))

Lambda函数通常与map(), filter(),sorted(), reduce()等函数一起使用。

numbers = [1, 2, 3, 4, 5]
 
# 使用 map() 函数将每个元素平方
squared_numbers = list(map(lambda x: x * x, numbers))
print(squared_numbers)
 
# 使用 filter() 函数过滤出偶数
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers)

2.9 解包运算符 (*和**)

解包运算符 *** 在函数调用和定义中都有重要的作用。

函数调用中的解包

  • *args 解包位置参数: 如果有一个列表或元组,并且想将它的元素作为单独的位置参数传递给函数,可以使用 * 运算符。
def my_function(a, b, c):
	print(a, b, c)
my_list = [1, 2, 3]
my_function(*my_list)  # 等价于 my_function(1, 2, 3)
 
my_tuple = (4, 5, 6)
my_function(*my_tuple)  # 等价于 my_function(4, 5, 6)
  • **kwargs 解包关键字参数: 如果有一个字典,并且想将它的键值对作为单独的关键字参数传递给函数,可以使用 ** 运算符。 字典的键必须是字符串,并且与函数的形式参数名匹配。
def my_function(name, age, city):
	print(f"Name: {name}, Age: {age}, City: {city}")
 
my_dict = {"name": "Alice", "age": 30, "city": "New York"}
my_function(**my_dict)  # 等价于 my_function(name="Alice", age=30, city="New York")

函数定义中的解包

  • *args 收集位置参数: 允许函数接收任意数量的位置参数,并将它们收集到一个元组中。
def my_function(*args):
	for arg in args:
		print(arg)
 
my_function(1, 2, 3, "a", "b")  # args 将会是 (1, 2, 3, "a", "b")
  • **kwargs 收集关键字参数: 允许函数接收任意数量的关键字参数,并将它们收集到一个字典中。
def my_function(**kwargs):
	for key, value in kwargs.items():
		print(f"{key}: {value}")
 
my_function(name="Eve", age=30, city="New York")  # kwargs 将会是{"name": "Eve", "age": 30, "city": "New York"}

示例:结合使用 *args**kwargs

def my_function(a, b, *args, **kwargs):
    print(f"a: {a}, b: {b}")
    print("args:", args)
    print("kwargs:", kwargs)
 
my_function(1, 2, 3, 4, name="Alice", age=30)
# 输出:
# a: 1, b: 2
# args: (3, 4)
# kwargs: {'name': 'Alice', 'age': 30}
 
my_list = [5,6]
my_dict = {'city': 'beijing', 'country': 'china'}
my_function(1, 2, *my_list, **my_dict)
 
# 输出:
# a: 1, b: 2
# args: (5, 6)
# kwargs: {'city': 'beijing', 'country': 'china'}

下一章