4.1 Python3 模块

在前面的几个章节中我们基本上是用 python 解释器来编程,如果你从 Python 解释器退出再进入,那么你定义的所有的方法和变量就都消失了。

为此 Python 提供了一个办法,把这些定义存放在文件中,为一些脚本或者交互式的解释器实例使用,这个文件被称为模块

Python 中的模块(Module)是一个包含 Python 定义和语句的文件,文件名就是模块名加上 .py 后缀

模块可以包含函数、类、变量以及可执行的代码。通过模块,我们可以将代码组织成可重用的单元,便于管理和维护。


目录

1. 模块的作用

2. 导入模块

2.1 基本导入

2.2 从模块导入特定内容

2.3 导入所有内容

2.4 给模块或导入项起别名

相对导入(在包内部使用)

3. __name__ 属性

3.1 模块测试代码

3.2 防止导入时执行代码

3.3 提供命令行接口

3.4 实际示例

4. dir() 函数

4.1 基本用法

4.2 实际应用场景

4.3 注意事项

4.4 与 help() 结合使用

4.5 自定义类的 __dir__ 方法

5. 标准模块库

6. 包

6.1 包的基本概念

6.2 __init__.py 文件的作用

6.3 包的导入方式

6.4 包的实际应用示例

6.5 包的安装与分发

6.6 现代Python包结构(推荐)

6.7 命名空间包(Python 3.3+)

6.8 最佳实践


1. 模块的作用

模块是包含 Python 定义和语句的文件,其作用包括:

  • 将相关代码组织在一起,提高代码的可维护性

  • 实现代码重用,避免重复编写相同功能

  • 命名空间管理,避免命名冲突

  • 便于大型项目的开发和维护


2. 导入模块

2.1 基本导入

  • 导入整个模块

  • 使用时需要通过模块名访问其中的内容:module_name.function_name

import math
print(math.sqrt(16))  # 使用模块名.成员名访问

2.2 从模块导入特定内容

  • 从模块中导入特定的函数、类或变量

  • 使用时可以直接使用名称,无需模块名前

from math import sqrt, pi
print(sqrt(16))  # 直接使用函数名
print(pi)       # 直接使用变量名

2.3 导入所有内容

  • 导入模块中的所有内容(除了以下划线开头的)
  • 可能导致命名冲突,不利于代码可读性

from math import *  # 不推荐,可能导致命名冲突
print(sin(1.57))

2.4 给模块或导入项起别名

  • 当模块名或函数名太长或有冲突时使用

import numpy as np
from math import factorial as fac

print(np.array([1, 2, 3]))
print(fac(5))  # 120

相对导入(在包内部使用)

  • 主要用于包内部的模块相互引用

  • 点号表示相对路径

from . import module_name      # 同目录下的模块
from .. import module_name     # 上级目录的模块
from .submodule import name    # 子模块中的内容

3. __name__ 属性

  • 当模块作为主程序直接运行时

    • __name__ 的值被设置为 '__main__'

  • 当模块被导入到其他模块中时

    • __name__ 的值被设置为模块的名称(即文件名去掉 .py 后缀)

3.1 模块测试代码

最常见的用法是在模块底部添加测试代码,这样当模块被直接运行时执行测试,而被导入时不执行:

def some_function():
    print("这是一个函数")

if __name__ == '__main__':
    # 只有直接运行这个模块时才会执行
    print("模块作为主程序运行")
    some_function()

3.2 防止导入时执行代码

# config.py
DEBUG = True

if __name__ == '__main__':
    # 这部分代码不会在导入时执行
    print("配置模块被直接运行")

3.3 提供命令行接口

# calculator.py
def add(a, b):
    return a + b

if __name__ == '__main__':
    import sys
    if len(sys.argv) == 3:
        a, b = map(int, sys.argv[1:3])
        print(f"结果是: {add(a, b)}")
    else:
        print("用法: python calculator.py <数字1> <数字2>")

3.4 实际示例

文件结构

project/
    ├── main.py
    └── mymodule.py

mymodule.py:

def hello():
    print("Hello from mymodule!")

print(f"在mymodule中,__name__ = {__name__}")

if __name__ == '__main__':
    print("mymodule被直接运行")
    hello()

main.py:

import mymodule

print("在main.py中")
mymodule.hello()

运行结果

  1. 直接运行 mymodule.py:

    在mymodule中,__name__ = __main__
    mymodule被直接运行
    Hello from mymodule!
  2. 运行 main.py:

    在mymodule中,__name__ = mymodule
    在main.py中
    Hello from mymodule!

说明:每个模块都有一个 __name__ 属性。

__name__ 与 __main__ 底下是双下划线, _ _ 是这样去掉中间的那个空格。


4. dir() 函数

dir() 是 Python 的一个内置函数,用于查看对象的属性和方法列表,或者当前作用域内的名称空间。

4.1 基本用法

1. 不带参数调用 - 查看当前作用域的名称

x = 10
y = "hello"

def my_function():
    pass

print(dir())  # 显示当前作用域中所有可用的名称
# 输出可能包含: ['__annotations__', '__builtins__', '__doc__', ..., 'my_function', 'x', 'y']

2. 带参数调用 - 查看对象的属性和方法

import math

# 查看math模块的所有属性和方法
print(dir(math))
# 输出可能包含: ['__doc__', '__loader__', '__name__', ..., 'cos', 'sin', 'sqrt']

my_list = [1, 2, 3]
# 查看列表的所有方法
print(dir(my_list))
# 输出可能包含: ['__add__', '__class__', ..., 'append', 'clear', 'copy', 'count', ...]

4.2 实际应用场景

1. 探索未知对象

import requests

# 查看requests模块的内容
print(dir(requests))

2. 调试时检查对象

class MyClass:
    def __init__(self):
        self.value = 42
    
    def show(self):
        print(self.value)

obj = MyClass()
print(dir(obj))  # 查看实例的属性和方法

3. 过滤出特定类型的成员

import math

# 获取math模块中所有不以双下划线开头的函数
math_funcs = [name for name in dir(math) if not name.startswith('__')]
print(math_funcs)

4.3 注意事项

  1. dir() 返回的是一个字符串列表,包含对象的所有属性、方法和类成员的名称

  2. 结果可能包含"魔术方法"(以双下划线开头和结尾的方法)

  3. 对于自定义类,可以定义 __dir__() 方法来定制 dir() 的输出

  4. dir() 不会列出内置函数和内置类型的名称,除非传入特定对象

4.4 与 help() 结合使用

import math

# 先查看math模块有哪些内容
print(dir(math))

# 然后查看特定函数的帮助
help(math.sqrt)

4.5 自定义类的 __dir__ 方法

class Person:
    def __init__(self, name, age):
        self.name = name
        self._age = age  # 约定为"私有"变量
    
    def __dir__(self):
        # 自定义dir()的输出,过滤掉以_开头的属性
        return [attr for attr in super().__dir__() if not attr.startswith('_')]

p = Person("Alice", 30)
print(dir(p))  # 不会显示_age属性

5. 标准模块库

Python 自带丰富的标准库模块,例如:

  • os - 操作系统接口

  • sys - 系统相关参数和函数

  • math - 数学函数

  • datetime - 日期和时间处理

  • json - JSON 编码和解码

  • re - 正则表达式

  • random - 生成随机数

  • urllib - URL 处理

  • collections - 容器数据类型


6. 包

包(Package)是Python组织模块的一种方式,它使用目录结构来组织相关的模块,使得项目结构更加清晰和可维护。

6.1 包的基本概念

包是一个包含__init__.py文件的目录,该目录下可以包含多个模块或子包。

my_package/           # 包目录
    ├── __init__.py   # 包的初始化文件
    ├── module1.py    # 模块1
    ├── module2.py    # 模块2
    └── subpackage/   # 子包
        ├── __init__.py
        └── module3.py

6.2 __init__.py 文件的作用

  • 标识一个目录为Python包

  • 可以包含包的初始化代码

  • 可以定义__all__变量控制from package import *的行为

  • 可以简化导入语句

示例__init__.py内容:

# 包级别的初始化代码
print(f"Initializing {__name__} package")

# 定义从包导入*时导入哪些模块
__all__ = ['module1', 'module2']

6.3 包的导入方式

基本导入

# 导入整个包
import my_package
my_package.module1.some_function()

# 导入包中的特定模块
from my_package import module1
module1.some_function()

# 导入子包中的模块
from my_package.subpackage import module3

相对导入(在包内部使用)

在包内部的模块中,可以使用相对导入:

# 在module2.py中导入同级的module1
from . import module1

# 在module3.py中导入上级包的module2
from .. import module2

# 在module3.py中导入上级包的module1中的特定函数
from ..module1 import some_function

6.4 包的实际应用示例

项目结构

calculator/
    ├── __init__.py
    ├── operations.py
    ├── advanced/
    │   ├── __init__.py
    │   └── scientific.py
    └── utils.py

operations.py

def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

scientific.py

from ..operations import add  # 相对导入上级包的模块

def square(x):
    return x * x

def cube(x):
    return x * x * x

使用包

from calculator.operations import add, subtract
from calculator.advanced.scientific import square

print(add(5, 3))      # 8
print(square(4))      # 16

6.5 包的安装与分发

创建可安装的包

需要添加setup.py文件:

from setuptools import setup, find_packages

setup(
    name="calculator",
    version="0.1",
    packages=find_packages(),
)

安装本地包

pip install -e .

6.6 现代Python包结构(推荐)

对于更复杂的项目,推荐以下结构:

project_name/
    ├── src/
    │   └── package_name/
    │       ├── __init__.py
    │       ├── module1.py
    │       └── subpackage/
    ├── tests/
    ├── docs/
    ├── setup.py
    ├── pyproject.toml
    └── README.md

6.7 命名空间包(Python 3.3+)

从Python 3.3开始,支持没有__init__.py文件的命名空间包:

namespace_pkg/
    ├── module_a.py
    └── module_b.py

6.8 最佳实践

  1. 保持__init__.py简洁,避免放入太多逻辑

  2. 使用明确的相对或绝对导入

  3. 避免循环导入

  4. 为包编写清晰的文档字符串

  5. 合理组织包结构,避免过深或过平的层次

包是Python模块化编程的核心概念,合理使用包可以大大提高代码的可维护性和复用性。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值