# 函数和模块

代码有很多种坏味道,重复是最坏的一种。

要写出高质量的代码首先要解决的就是重复代码的问题。

# 函数相关

# 函数的定义

在 python 中,使用关键字 def 定义函数。它由函数名,参数,函数主题组成。

  • 每一个函数都有一个响亮的名字,但通常和变量名一样,见名识意。

  • 函数的参数叫形参

  • 函数一般通过 return 关键字返回一个值。


def greet(name):  
    """这个函数会打印一条包含传入名字的问候语。"""  
    print(f"Hello, {name}!")  
  
# 调用函数  
greet("World")  # 输出: Hello, World!  
greet("Python")  # 输出: Hello, Python!

函数定义后面的三引号括起来的内容是函数的文档字符串,用于解释函数的功能和用法。

# 函数的参数

在 python 中,参数是函数定义中的一部分,用于接收传递给函数的值,参数定义了函数期望接收的数据类型和数量。当你调用函数时,传递给函数的值成为实参。

# 参数的类型
  • 位置参数:数定义中的参数按照从左到右的顺序排列,并在调用函数时按照同样的顺序传递值。
def greet(name, age):  
    print(f"Hello, {name}. You are {age} years old.")  
  
greet("Alice", 30)  # 正确调用,按照位置传递参数
  • 关键字参数:在调用函数时,你可以通过参数名(关键字)来指定参数的值。这允许你以任意顺序传递参数,只要确保每个参数名都与其对应的值匹配。

  • 默认参数:在函数定义中,可以为参数指定默认值。如果调用函数时没有提供该参数的值,则使用默认值。

  • 可变位置参数:使用 *args 语法,可以允许函数接收任意数量的位置参数,并将它们作为元组处理。

def print_numbers(*numbers):  
    for num in numbers:  
        print(num)  
  
print_numbers(1, 2, 3, 4)  # 输出 1 2 3 4

  • 可变关键字参数:使用 **kwargs 语法,可以允许函数接收任意数量的关键字参数,并将它们作为字典处理。
def print_info(**info):  
    for key, value in info.items():  
        print(f"{key}: {value}")  
  
print_info(name="Alice", age=30)  # 输出 name: Alice 和 age: 30

# 模块相关

在 python 中,每个文件就代表了一个模块,模块可以定义函数,类,变量。然后这些定义可以被其他程序或模块导入和使用。模块是组织代码的一种方式,有助于代码重用,避免命名冲突,提高代码的可维护性。

  • 代码重用:其他程序可以通过关键字 import 来导入模块中的函数,类或者变量。

  • 命名空间:有助于避免命名冲突。

  • 组织代码:将相关的代码组织在一起,易于阅读和维护。

  • 可扩展性:方便添加新功能,并在需要的时候导入到主程序即可。

  • 导入方式:可以使用关键字 import 导入整个模块,使用 from ... import ... 语句导入模块中的特定函数,类,或者变量。

# 导入方式

1、导入整个模块

使用模块中的函数时,需要加上模块名作为前缀。


import math

result = math.sqrt(16)
print(result)

2、从模块中导入特定的函数或者变量

在使用时,直接使用函数名,不需要加模块名前缀


from math import sqrt

result = sqrt(16)
print(result)

3、从模块中导入多个特定的函数或变量

在使用时,直接使用函数名,不需要加模块名前缀

from math import sqrt,pow

# 直接使用函数名  
result1 = sqrt(16)  
result2 = pow(2, 3)  
print(result1)  # 输出: 4.0  
print(result2)  # 输出: 8.0

4、导入模块并使用别名 as 关键字

使用别名作为模块名前缀

import math as m  
  
result = m.sqrt(16)  
print(result)  # 输出: 4.0

5、从模块中导入所有内容(通常不推荐,因为可能导致命名冲突)

from math import *

result1 = sqrt(16) 
print(result1)  # 输出: 4.0  

尽管使用 from module import * 可以避免在代码中频繁地写模块名前缀,但这通常不是一个好的编程习惯,因为它可能会导致命名冲突和难以追踪的依赖关系。在大型项目中,最好明确地从模块中导入你需要的函数或变量。

另外,如果导入的模块除了定义函数之外,还有可执行的代码,那么 python 解释器在导入这个模块时就会执行这些代码,如果想要在导入模块的时候不执行这些代码,可以在模块中将这些执行代码放到入口中:


if __name__ == '__main__':
    .
    .
    .

# 变量的作用域

# 局部作用域

在函数或方法内部定义的变量具有局部作用域。这意味着这些变量只能在函数或方法内部被访问。

当函数或方法执行完毕后,这些变量就会被销毁(除非它们被作为返回值或通过某种方式传递到外部作用域)。

# 嵌套作用域

如果一个函数内部定义了另一个函数,那么内部函数可以访问外部函数的变量(除了那些被标记为nonlocal或global的)。

# 全局作用域

在所有函数和方法之外定义的变量具有全局作用域。这意味着这些变量可以在整个程序中被访问。

在函数内部,你可以通过global关键字来声明一个变量是全局的,从而可以在函数内部修改它。

# 内置作用域

内置作用域是Python解释器在启动时创建的,它包含了所有内置函数和异常的名字。

我们不能在这个作用域中定义新的变量,也不能删除这个作用域中的变量。

例如,len(), int(), True, False, 和 None 等都是内置作用域中的变量。