Python程序教程

您现在的位置是:首页 >  Python

当前栏目

Python模块

Python,模块
2025-04-07 09:01:33 时间

一、模块概述

  • 命名空间 由于在Python中一切皆为对象(Object), 想要好好理解Module和Package,一定要先理解Namespace的概念。 所谓Namespace,是指标示符的可见范围。对于Python而言,常见的Namespace主要有以下几种
    • Build-in Namespace (内建命名空间)
    • Global Namespace (全局命名空间)
    • Local Namespace (局部命名空间)

    有了命名空间的概念,可以有效的解决函数或者是变量重名的问题。不同的命名空间中允许出现相同的函数名或者 是变量名。它们彼此之间不会相互影响,例如在Namespace A和B中同时有一个名为var的变量,对A.var赋值并不 会改变B.var的值。

  • 为什么使用模块? 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越难以维护
  • 模块概述 为了编写可维护性的代码,我们会把很多函数进行分组,分别放到不同的文件里去。这样,每个文件包含的代码就相对较少,大多数编程语言都是采用这种方式来组织代码的,在python中,一个.py文件就称之为一个模块 其中定义的所有函数或者是变量都属于这个Module。这个Module 对于所有函数而言就相当于一个全局的命名空间。而每个函数又都有自己局部的命名空间。
  • 优点
    • 提高了代码的可维护性
    • 提高了代码的复用度,编写代码不必从零开始,当一个模块编写完成,就可以在其他地方引用
    • 引用其他模块,包含python内置模块和第三方模块
    • 避免函数名和变量名等命名的冲突
  • 模块分类
    • 标准库模块
    • 第三方模块
    • 自定义模块

二、使用标准库中的模块

time

import time
now = time.strftime("%Y-%m-%d %H:%M:%S")  # 获取当前时间
print(now)

random

import random
random_num = random.randrange(3)  # 返回012的随机数
print(random_num)

三、使用自定义模块

新建一个名为speak.py文件

# speak.py 
'''
This is only a test module
'''
name = 'zutuanxue_com'
age = 18

def speak():
  print("zutuanxue_com is a very good man!")

import 语句

  • 作用 导入模块/包
  • 格式 import module1[, module2[, module3[, ……]]] import module1 as 别名[, module2[, module3[, ……]]] 起别名
  • 注意 一个模块只会被导入一次,不管你执行了多少次import,有效的防止导入模块被一次次的执行
  • 使用模块中的内容 module.方法/类/变量

不起别名实例

>>> import speak  # 导入speak模块 
>>> speak.name  # 获取模块speak中name的值
zutuanxue_com
>>> speak.age  # 获取模块speak中age的值
18
>>> speak.speak()  # 调用模块中speak方法
zutuanxue_com is a very good man!
>>> print speak.__doc__  # 获取模块说明
This is only a test module

起别名实例

<span class="hljs-meta">>>> </span><span class="hljs-keyword">import</span> speak <span class="hljs-keyword">as</span> s  <span class="hljs-comment"># 导入speak模块 并起别名为s</span>
<span class="hljs-meta">>>> </span>s.name  <span class="hljs-comment"># 获取模块speak中name的值</span>
zutuanxue_com
<span class="hljs-meta">>>> </span>s.age  <span class="hljs-comment"># 获取模块speak中age的值</span>
<span class="hljs-number">18</span>
<span class="hljs-meta">>>> </span>s.speak()  <span class="hljs-comment"># 调用模块中speak方法</span>
zutuanxue_com <span class="hljs-keyword">is</span> a very good man!
<span class="hljs-meta">>>> </span><span class="hljs-keyword">print</span> s.__doc__  <span class="hljs-comment"># 获取模块说明</span>
This <span class="hljs-keyword">is</span> only a test module

from … import 语句

  • 作用 从模块中导入一些指定的部分
  • 格式 from module import name1[, name2[, name3[, ……]]]

实例

<span class="hljs-meta">>>> </span><span class="hljs-keyword">from</span> speak <span class="hljs-keyword">import</span> name,age,speak  <span class="hljs-comment"># 从speak模块导入 name,age,speak</span>
<span class="hljs-meta">>>> </span>name  <span class="hljs-comment"># 获取模块speak中name的值</span>
zutuanxue_com
<span class="hljs-meta">>>> </span>age  <span class="hljs-comment"># 获取模块speak中age的值</span>
<span class="hljs-number">18</span>
<span class="hljs-meta">>>> </span>speak()  <span class="hljs-comment"># 调用模块中speak方法</span>
zutuanxue_com <span class="hljs-keyword">is</span> a very good man!

from … import * 语句

  • 概述 将模块中所有非下划线开头的成员都导入
  • 作用 把一个模块中所有的内容全部导入当前命名空间
  • 格式 from modulename import *
  • 注意 不应该过多使用,很可能造成变量名的冲突

实例

<span class="hljs-meta">>>> </span><span class="hljs-keyword">from</span> speak <span class="hljs-keyword">import</span> *  <span class="hljs-comment"># 会将speak模块中非下划线开头的成员都导入当前命名空间中</span>
<span class="hljs-meta">>>> </span>name  <span class="hljs-comment"># 获取模块speak中name的值</span>
zutuanxue_com
<span class="hljs-meta">>>> </span>age  <span class="hljs-comment"># 获取模块speak中age的值</span>
<span class="hljs-number">18</span>
<span class="hljs-meta">>>> </span>speak()  <span class="hljs-comment"># 调用模块中speak方法</span>
zutuanxue_com <span class="hljs-keyword">is</span> a very good man!

四、__all__接口暴露

概述

代码中是不提倡用 from xxx import * 的写法的,但是在 console 调试的时候图个方便还是很常见的。如果一个模块 spam 没有定义 __all__,执行 from spam import * 的时候会将 spam 中非下划线开头的成员都导入当前命名空间中,这样当然就有可能弄脏当前命名空间。如果显式声明了 __all__import * 就只会导入 __all__ 列出的成员。如果 __all__ 定义有误,列出的成员不存在,还会明确地抛出异常,而不是默默忽略。

格式

__all__ = ["name1", "name2"...]

作用

Python不像 Ruby 或者 Java,Python 没有语言原生的可见性控制,而是靠一套需要大家自觉遵守的”约定“下工作。比如下划线开头的应该对外部不可见。同样,__all__ 也是对于模块公开接口的一种约定,比起下划线,__all__ 提供了暴露接口用的”白名单“。一些不以下划线开头的变量(比如从其他地方 import 到当前模块的成员)可以同样被排除出去。

新建test_all.py

# test_all.py
'''
This is only a test __all__ module
'''

__all__ = ["name", "speak"]  # 排除了 age

name = 'zutuanxue_com'
age = 18

def speak():
  print("zutuanxue_com is a very good man!")

五、模块循环引用

概述

出现循环引用其实就是模块之间发生了相互依赖,A依赖B,B依赖A,这样他们直接相互依赖,引用的时候就会出现者循环引用(交叉引用)

现象

有两个模块moduleA 和 moduleB

moduleA.py

from moduleB import b

def a():
    print('我是A模块的a方法')
    moduleB.b()
def c():
    print('我是A模块的c方法')

if __name__ == '__main__':
    a()

moduleB.py

   <span class="hljs-keyword">from</span> moduleA <span class="hljs-keyword">import</span> c
   
   <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">b</span><span class="hljs-params">()</span>:</span>
       print(<span class="hljs-string">'我是B模块的b方法'</span>)
       c()

导入的实质

导入其实是要将 被导入模块所有的顶格代码都执行一遍,遇到函数和类的定义会作申明 如果b模块中有这么一句

print(<span class="hljs-string">'我是B模块'</span>)

你在a模块impot b时就会 执行 print(‘bbb’)这一句 回到循环引用中,首先导入B,进入B中,发现B中又导入了A又回到A中,但是A又导入B这就形成了循环引用

解决方式1(直接导入模块名,通过模块调用其中的函数)

moduleA.py

import moduleB

def a():
    print('我是A模块的a方法')
    moduleB.b()
def c():
    print('我是A模块的c方法')


if __name__ == '__main__':
    a()

moduleB.py

<span class="hljs-keyword">import</span> moduleA

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">b</span><span class="hljs-params">()</span>:</span>
    print(<span class="hljs-string">'我是B模块的b方法'</span>)
    moduleA.c()

解决方式2(使用延迟导入(lazy import))

内部导入

<span class="hljs-string">"""
moduleB.py
"""</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">b</span><span class="hljs-params">()</span>:</span>
    <span class="hljs-keyword">from</span> moduleA <span class="hljs-keyword">import</span> c
    print(<span class="hljs-string">'我是B模块的b方法'</span>)
    c()

六、__name__属性

  • 概述 每个模块都有一个__name__属性,当其值为“main”时表明该模块自身在运行,否则是被当做模块导入,此时值为模块的名字

实例

# speak.py 
'''
This is only a test module
'''
name = 'zutuanxue_com'
age = 18

def speak():
  print("zutuanxue_com is a very good man!")
  
if __name__ == '__main__': 
   speak()

__name__作用

模块就是一个可执行的python文件,一个模块被另一个模块导入,想让模块中的某一段代码不执行,可以使用__name__属性来使程序隐藏该段代码,当自身执行时在执行该块代码。一般作为判断是否是作为主运行文件

扩展

以后主要用于程序入口使用(项目启动文件中使用)

"""
Main.py
"""
def main():
	pass

if __name__ == '__main__':
	main()

七、包

需求

如果不同的人编写的模块名相同怎么办?

解决

为了避免模块名的冲突,python又引入了按目录来组织模块的方法,称为包(package)

特点

引入包以后,只要顶层包名不与别人冲突, 那么所有的模块都不会与别人冲突

注意

每个包目录下都会有一个名为__init__.py的文件,说明这个目录是个python包,还可以导出包中的内容

建包

新建文件夹名称为lucky_package文件夹

目录结构

project/
	lucky_package/
  	__init__.py  # 声明lucky_package为一个包
    speak.py  # 模块speak
  test.py  # 用于测试lucky_package包的使用

实现 方式一 通过pycharm直接创建Python包 选择模块 -> New -> Python Package

输入包名

点击OK

  • 方式二 手动创建
    • 模块 -> New -> Directory
  • 输入 lucky_package
  • 点击OK
  • lucky_package -> New -> Python File
  • 输入文件名称为 __init__.py
  • 点击 OK

包内创建模块

speak.py

<span class="hljs-comment"># speak.py </span>
<span class="hljs-string">'''
This is only a test module
'''</span>
name = <span class="hljs-string">'zutuanxue_com'</span>
age = <span class="hljs-number">18</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">speak</span><span class="hljs-params">()</span>:</span>
  print(<span class="hljs-string">"zutuanxue_com is a very good man!"</span>)
  
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>: 
   speak()

使用

test.py

第一种导入方式使用

>>> from lucky_package import speak  # 从zutuanxue_com_package包导入speak模块
>>> speak.name  # 获取模块speak中name的值
zutuanxue_com
>>> speak.age  # 获取模块speak中age的值
18
>>> speak.speak()  # 调用模块中speak方法
zutuanxue_com is a very good man!

导包重命名

<span class="hljs-meta">>>> </span><span class="hljs-keyword">from</span> lucky_package <span class="hljs-keyword">import</span> speak <span class="hljs-keyword">as</span> s  <span class="hljs-comment"># 从zutuanxue_com_package包导入speak模块并重命名为s</span>
<span class="hljs-meta">>>> </span>s.name  <span class="hljs-comment"># 获取模块speak中name的值</span>
zutuanxue_com

第二种导入方式

>>> from lucky_package.speak import name,age,speak  # 从lucky_package包speak模块导入 name,age,speak
>>> name  # 获取模块speak中name的值
zutuanxue_com
>>> age  # 获取模块speak中age的值
18

第三种导入方式

>>> from lucky_package.speak import *  # 从lucky_package包speak模块导入 所有成员
>>> name  # 获取模块speak中name的值
zutuanxue_com
>>> age  # 获取模块speak中age的值
18

第四种导入方式

>>> import lucky_package.speak  # 导入lucky_package里speak包
>>> lucky_package.speak.name  # 获取name的值
zutuanxue_com

第五种导入方式

import lucky_package.speak as s # 导入lucky_package里speak包 s.name # 获取name的值 zutuanxue_com

填充包__init__.py代码

方式一 在init.py中 导入模块

__init__.py

from . import speak

使用

<span class="hljs-meta">>>> </span><span class="hljs-keyword">from</span> lucky_package <span class="hljs-keyword">import</span> speak   <span class="hljs-comment"># 导入lucky_package里speak包</span>
<span class="hljs-meta">>>> </span>speak.name  <span class="hljs-comment"># 获取name的值</span>
zutuanxue_com

方式二

在init.py中 导入模块所有成员

__init__.py

from .speak import * 

使用

<span class="hljs-meta">>>> </span><span class="hljs-keyword">from</span> lucky_package <span class="hljs-keyword">import</span> *   <span class="hljs-comment"># 导入lucky_package里speak包</span>
<span class="hljs-meta">>>> </span>name  <span class="hljs-comment"># 获取name的值</span>
zutuanxue_com

注意

不建议这样使用方式