进阶8:模块

python模块

模块介绍

在 Python 中,一个.py文件就是一个模块。在 Python ,万物皆对象,模块也不例外。通过模块,可以有效的组织代码结构,让代码结构更加清晰

Python 模块是一种组织和管理代码的方式,可以将相关功能的代码分组到单独的文件中。模块可以包含函数、类和变量,甚至可以包括可执行的代码。Python 标准库中提供了许多内置模块,同时,开发者也可以创建自己的模块。

系统模块

常见的 Python 系统模块包括:

  1. os: 提供了与操作系统进行交互的功能,如文件和目录操作。
  2. sys: 提供了访问 Python 解释器使用或维护的变量和与解释器进行交互的功能。
  3. math: 提供了数学函数,如平方根、sin、cos 等。
  4. json: 提供了 JSON 数据的编码和解码功能。
  5. datetime: 提供了处理日期和时间数据的类。
  6. random:用于生成随机数。这个模块可以用于获取随机数、打乱列表顺序、从序列中随机选择元素等
  7. time:提供与时间相关的各种函数。这个模块可以用于获取当前时间、计算时间差、暂停执行等。
  8. functools:提供了高阶函数,用于函数式编程风格。这个模块包含用于处理和扩展函数功能的工具。

自定义模块

os模块

import os

# 获取当前工作目录
current_directory = os.getcwd()
print("当前工作目录:", current_directory)

# 列出当前目录下的所有文件和子目录
files_and_dirs = os.listdir(current_directory)
print("目录内容:", files_and_dirs)

# 创建新目录
os.mkdir('new_directory')

# 删除目录
os.rmdir('new_directory')
进阶8:模块

sys模块

   import sys

   # 打印 Python 解释器的版本信息
   print("Python 版本:", sys.version)

   # 打印命令行参数
   print("命令行参数:", sys.argv)

   # 退出程序
   sys.exit()
进阶8:模块

math模块

import math

# 计算平方根
print("平方根:", math.sqrt(16))

# 计算正弦值
print("sin(π/2):", math.sin(math.pi / 2))

# 计算阶乘
print("5的阶乘:", math.factorial(5))
进阶8:模块

json模块

import json

# 将 Python 对象编码为 JSON 字符串
data = {'name': 'Alice', 'age': 25, 'city': 'New York'}
json_str = json.dumps(data)
print("JSON 字符串:", json_str)

# 将 JSON 字符串解码为 Python 对象
decoded_data = json.loads(json_str)
print("解码后的数据:", decoded_data)
进阶8:模块

datetime模块

   from datetime import datetime, timedelta

   # 获取当前日期和时间
   now = datetime.now()
   print("当前日期和时间:", now)

   # 格式化日期
   formatted_date = now.strftime("%Y-%m-%d %H:%M:%S")
   print("格式化日期:", formatted_date)

   # 计算两天后的日期
   future_date = now + timedelta(days=2)
   print("两天后的日期:", future_date)
进阶8:模块

random模块

   import random

   # 生成随机数
   random_number = random.randint(1, 10)
   print("随机数:", random_number)

   # 打乱列表顺序
   items = [1, 2, 3, 4, 5]
   random.shuffle(items)
   print("打乱后的列表:", items)

   # 随机选择列表中的元素
   choice = random.choice(items)
   print("随机选择的元素:", choice)
进阶8:模块

time模块

   import time

   # 获取当前时间戳
   current_time = time.time()
   print("当前时间戳:", current_time)

   # 暂停执行2秒
   print("开始暂停")
   time.sleep(2)
   print("暂停结束")

   # 计算函数执行时间
   start_time = time.time()
   # 模拟长时间运行的代码
   time.sleep(2)
   end_time = time.time()
   print("执行时间:", end_time - start_time, "秒")
进阶8:模块

functools模块

   from functools import lru_cache

   # 使用缓存装饰器优化斐波那契数列计算
   @lru_cache(maxsize=None)
   def fibonacci(n):
       if n < 2:
           return n
       return fibonacci(n - 1) + fibonacci(n - 2)

   print("斐波那契数列第10项:", fibonacci(10))
进阶8:模块

自定义模块

使用 import 导入自定义模块

创建一个 Python 文件
创造一个新的 Python 文件,并在其中定义函数、类或者变量。例如,创建一个文件 mymodule.py

# mymodule.py

def greet(name):
   return f"Hello, {name}!"

class Person:
   def __init__(self, name):
       self.name = name

   def say_hello(self):
       return f"{self.name} says hello."

pi = 3.14159

保存文件:
将文件保存到你的项目目录中或任何可以被 Python 解释器找到的路径下

使用自定义模块

导入模块:

在其他 Python 脚本中,可以通过 import 语句导入这个模块。

import mymodule

print(mymodule.greet("Alice"))

person = mymodule.Person("Bob")
print(person.say_hello())

print("Value of pi:", mymodule.pi)
进阶8:模块

导入模块时,需要创建该模块的对象,也就会执行该文件的所有代码

进阶8:模块

从模块中导入特定项

导入指定模块中的指定成员,当使用 from-import 方式导入时,不需要再使用模块名.成员 形式

可以在当前文件中,直接使用成员名,相当于将导入的成功复制到了本地一份,可以使用谁导入谁,更加节省资源

from mymodule import greet, Person

print(greet("Alice"))
person = Person("Bob")
print(person.say_hello())
进阶8:模块

特例:

使用 from-import 方式也可以将整个模块中的成员都导入进来,但是这种情况下不能使用别名

from mymodule import *

使用别名

# 将模块起别名
import mymodule as mm
print(mm.greet("Alice"))

# 将指定成员起别名
from mymodule import greet as hello
print(hello("Charlie"))
进阶8:模块

模块导入的命名冲突问题

问题一:私有变量未能导入

在模块中,定义三个变量

x = 1 # 全局变量,模块间公有变量
_y = 2 # 私有变量,文件内私有变量
__z = 3 # 私有变量,一般出现在类中,不直接在模块中定义,这里只是借用
进阶8:模块
进阶8:模块

最终输出:

进阶8:模块

在使用 from module import * 导入模块时,不会将私有属性导入

进阶8:模块

通过__all__魔法属性可以改变 from-import 的导入规则,但是一般不会使用”__all__“属性

进阶8:模块
进阶8:模块

问题二:模块导入的命名冲突

如果文件中有相同的变量,后面的会把前面的覆盖掉,这里 x 被替换成一个对象

进阶8:模块

如何避免这种问题:

1、使用别名:
你可以在导入时为模块指定一个别名,这样即使有命名冲突,也可以通过别名来区分。

from module1 import function as func1
from module2 import function as func2

func1()  # 使用 module1 中的 function
func2()  # 使用 module2 中的 function

2、使用模块的完整路径:

如果模块很小,可以直接使用模块名来调用其函数,这样不需要对模块下的变量进行区分

import module1
import module2

module1.function()
module2.function()

3、按需导入模块

如果只是偶尔需要某个模块,可以在函数内部导入,减少命名冲突的可能性

def some_function():
   import module1
   module1.function()

模块导入顺序

在 Python 中,模块导入的顺序通常可以遵循以下顺序,以保持清晰和组织良好的代码结构:

  1. 自定义模块:最后是你的本地模块或包的导入。这些一般是你自己编写的或者在你的项目中自定义的模块。
  2. 系统模块:Python 内置库的导入放在最前面。标准库包括 ossysdatetime 等。
  3. 第三方模块:次于标准库的导入顺序是使用 pip 或其他包管理工具安装的第三方库。例如 numpypandasrequests 等。

查找顺序:

  • 当前目录:首先,Python会在执行文件的当前目录中查找。如果你是在交互式解释器中执行代码,则会在解释器启动时的当前路径中查找。
  • 环境变量PYTHONPATH:接下来,Python会查找由环境变量PYTHONPATH指定的目录。这个环境变量包含了一系列目录,其格式与操作系统的PATH环境变量类似。各个目录之间通常用冒号(:)或分号(Windows上;)分隔。
  • 标准库目录:然后,Python会查找安装Python时包括的标准库目录。这包括所有核心的标准库模块。
  • 第三方包的目录:接下来,Python会查找已安装的第三方包和模块的目录,这些通常位于site-packages目录中。

如果在所有这些步骤中未找到模块,Python解释器将引发ModuleNotFoundError

可以通过检查sys.path来查看模块的查找路径。sys.path是一个列表,列出了所有可能查找模块的位置。你可以通过以下方式查看和修改它:

import sys

# 查看当前的路径列表
print(sys.path)

# 可以通过直接修改列表来临时添加目录
sys.path.append('/path/to/your/module')

__name__属性设置程序入口

在 Python 中,__name__ 是一个特殊的属性,用于确定模块的名称。根据模块是被直接运行还是被导入,这个属性的值会有所不同:如果当前模块文件是主动执行时,__name__得到的结果是字符串__main__表示这是程序的入口;如果被动执行时(被导入时),得到的结果就是当前模块文件的文件名。下面是对 __name__ 属性的详细解释:

  1. 作为脚本直接运行时
    如果一个 Python 脚本是被直接运行的,那么 __name__ 的值将被设置为字符串 '__main__'。这种情况下,通常会用一个条件语句来执行某些仅在直接运行时才需要执行的代码。这是通过以下结构实现的:
if __name__ == "__main__":
    # 此处的代码仅在脚本被直接运行时执行
    print("This script is being run directly")
  1. 作为模块被导入时
    如果这个文件作为模块被导入到另一个脚本中,__name__ 的值将是模块的名称。在这种情况下,上述条件不成立,if 语块中的代码不会执行。例如:
# file: mymodule.py
print("This will always print regardless of execution context")
   
if __name__ == "__main__":
    print("This will only print if mymodule.py is run directly")
进阶8:模块
# another_script.py
import mymodule
# 输出只会有 "This will always print regardless of execution context"
进阶8:模块

可以通过if __name__ == "__main__" 来判断是否为程序的入口,这个属性的主要用途是在模块的编写中提供一种测试模块功能的方式,而不希望测试代码在模块被作为库导入其他脚本时执行。这样可以确保模块中的测试代码和主要功能代码之间的分离。

python 包

在 Python 中,一个包(package)是一个包含多个模块的目录(可以看作是管理模块的目录文件夹)。包的主要功能是组织和管理代码,以便更好地维护和重用。包可以包含子包、模块以及特殊的文件 __init__.py__init__.py 可以是一个空文件,也可以包含包的初始化代码。

包的结构示例

一个简单的包结构可能如下:

mypackage/
    __init__.py
    mymodule.py
    subpackage/
        __init__.py
        submodule.py

创建包

创建第一个包和python文件

进阶8:模块
进阶8:模块

在目录下创建一个 py 文件

进阶8:模块
进阶8:模块
进阶8:模块

创建第二个包,这次使用 python 自带的

进阶8:模块

python 软件包会自动创建__init__.py用来初始化权限,但是创建目录和 python 软件包对于解释起来说都是一样的包

进阶8:模块

创建 b.py

进阶8:模块

导入包中的模块

如何导入包中的模块及其成员

导入整个模块

如果你想导入整个模块,可以使用 import 语句。假设你有一个包 mypackage,其中有一个模块 mymodule.py

import mypackage.mymodule

# 使用模块中的函数或类
mypackage.mymodule.some_function()

包中的模块名称比较长,所以说可以使用别名的方式来简化:

import mypackage.mymodule as mmd

# 使用模块中的函数或类
mmd.some_function()

就上面例子:

import package01.a
print(package01.a.m)
进阶8:模块
import package01.a as mmd

# 使用模块中的函数或类
print(mmd.m)
进阶8:模块

从包中导入模块

进阶8:模块

从模块中导入特定成员

你也可以从模块中导入特定的函数、类或变量,使用 from ... import ... 语句:

from mypackage.mymodule import some_function, SomeClass

# 使用导入的函数或类
some_function()
obj = SomeClass()
进阶8:模块

导入所有成员
如果你想从模块中导入所有成员,可以使用星号 *。注意,这种方式不推荐,因为它可能导致命名冲突:

注意:如果只导到包的位置,那么通过这个包找模块时会报错,因为不确定要导入哪个模块需要在包中的__init__.py中高速解释器,当导入包时,应该导入哪些

进阶8:模块

__init__.py 的作用

__init__.py 文件可以是一个空文件,但它的存在目的是将目录标识为一个包。在 Python 3.3 及以后版本,__init__.py 文件可以没有,但如果你需要执行一些包初始化操作(例如,设置一些包级别变量),可以在这个文件中进行。

__init__.py 是一个特殊的 Python 文件,有几个重要的作用:

  • 标识包 (Package):当一个目录中包含 __init__.py 文件时,Python 将其视作一个包。 这意味着你可以从这个目录中导入模块和子包。在 Python 3.3 之后,即使没有 __init__.py 文件,目录也可以被当作包。然而,最好还是保留这个文件以确保兼容性。
  • 初始化代码:__init__.py 可以包含初始化代码,这些代码在包第一次被导入时运行。例如,你可以在这里初始化一些包级变量、类或导入子模块。
  • 限制导入内容:通过在 __init__.py 文件中定义 __all__ 列表,可以控制从这个包中使用 from package import * 语法时导入的内容。

标识包的使用:

上面给我们也知道只导到包的位置,那么通过这个包找模块时会报错,那么现在我们尝试在__init__.py中标识包

创建多层目录

cool/
    ljh/
        www/
            __init__.py
            a.py(n = 1)
            b.py(m = 2)
进阶8:模块

错误复现:当 import 一个目录,而不是具体的某个模块时,会进行报错

进阶8:模块

使用__init__.py在当前目录引入模块 a,b,使用 from . import 模块名 形式进行指定

进阶8:模块

成功运行

进阶8:模块

同理,使用 from-import 方式也需要在__init__中明确指出可以被导入的模块有哪些。

进阶8:模块
进阶8:模块

限制导入内容

__all__在 init 文件中的用法

通过在 __init__.py 文件中定义 __all__ 列表,可以限制从这个包中使用 from package import * 语法时导入的内容。

假设有如下目录结构:

mypackage/
    __init__.py
    module1.py
    module2.py

module1.py

def module1_function():
    print('module1')

module2.py

def module2_function():
    print('module2')

__init__.py 文件中的内容:

# 初始化代码
print("Importing mypackage")

# 导入子模块
from .module1 import *
from .module2 import *

__all__ = ["module1_function", "module2_function"]

调用文件test1.py

from mypackage import *

module1_function()
module2_function()

这样,当你导入 mypackage 时,就会执行 __init__.py 文件中的代码,并且 mypackage 包会自动导入 module1module2 模块,并且只导出 __all__ 列表中指定的内容。

进阶8:模块

原来的例子:

进阶8:模块
进阶8:模块

假如在__init__中去掉 b

进阶8:模块
进阶8:模块

模块导入总结:

导入模块:

  • 导入整个模块:import 包名.模块名 -> 使用:包名.模块名.成员
  • 导入模块指定别名:import 包名.模块名 as 模块别名 -> 使用:别名.成员

导入成员:

  • 导入特定成员:from 包名.模块名 import 成员名 ->直接使用成员
  • 导入多个成员:from 包名.模块名 import 成员1,成员2... ->直接使用成员
  • 导入特定成员指定别名:from 包名.模块名 import 成员别名 ->直接使用成员
  • 使用通配符导入所有成员(不推荐):from 模块名 import * -> 直接使用成员

导入整个包:

  • 通常,Python 不支持直接导入整个包,而是导入包下的模块或成员。不过,如果包中包含 __init__.py 文件,可以在该文件中制定导入行为。在__init__.py中:from 目录 import 模块名

发布者:LJH,转发请注明出处:https://www.ljh.cool/42019.html

(0)
上一篇 2024年11月14日 下午4:30
下一篇 3天前

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注