组团学

Python模块

阅读 (190586)

一、模块概述

  • 命名空间

    由于在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

    起别名实例

    >>> import speak as s # 导入speak模块 并起别名为s >>> s.name # 获取模块speak中name的值 zutuanxue_com >>> s.age # 获取模块speak中age的值 18 >>> s.speak() # 调用模块中speak方法 zutuanxue_com is a very good man! >>> print s.__doc__ # 获取模块说明 This is only a test module
  • from … import 语句

    • 作用

      从模块中导入一些指定的部分

    • 格式

      from module import name1[, name2[, name3[, ……]]]

    实例

    >>> from speak import name,age,speak # 从speak模块导入 name,age,speak >>> name # 获取模块speak中name的值 zutuanxue_com >>> age # 获取模块speak中age的值 18 >>> speak() # 调用模块中speak方法 zutuanxue_com is a very good man!
  • from … import * 语句

    • 概述

      将模块中所有非下划线开头的成员都导入

    • 作用

      把一个模块中所有的内容全部导入当前命名空间

    • 格式

      from modulename import *

    • 注意

      不应该过多使用,很可能造成变量名的冲突

    实例

    >>> from speak import * # 会将speak模块中非下划线开头的成员都导入当前命名空间中 >>> name # 获取模块speak中name的值 zutuanxue_com >>> age # 获取模块speak中age的值 18 >>> speak() # 调用模块中speak方法 zutuanxue_com is 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

    from moduleA import c def b(): print('我是B模块的b方法') c()
  • 导入的实质

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

    print('我是B模块')

    你在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

    import moduleA def b(): print('我是B模块的b方法') moduleA.c()
  • 解决方式2(使用延迟导入(lazy import))

    内部导入

    """ moduleB.py """ def b(): from moduleA import c print('我是B模块的b方法') 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

屏幕快照 20191225 下午2.52.15.png

输入包名

屏幕快照 20191225 下午2.52.447256895.png

点击OK

屏幕快照 20191225 下午2.52.54.png

  • 方式二 手动创建

    • 模块 -> New -> Directory

屏幕快照 20191225 下午2.56.17.png

  • 输入 lucky_package

屏幕快照 20191225 下午2.56.36.png

  • 点击OK

屏幕快照 20191225 下午2.56.48.png

  • lucky_package -> New -> Python File

屏幕快照 20191225 下午2.56.52.png

  • 输入文件名称为 __init__.py

屏幕快照 20191225 下午2.57.00.png

  • 点击 OK

屏幕快照 20191225 下午2.57.00.png

  • 包内创建模块

    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!") if __name__ == '__main__': 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!

      导包重命名

      >>> from lucky_package import speak as s # 从zutuanxue_com_package包导入speak模块并重命名为s >>> s.name # 获取模块speak中name的值 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

      使用

      >>> from lucky_package import speak # 导入lucky_package里speak包 >>> speak.name # 获取name的值 zutuanxue_com
    • 方式二

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

      __init__.py

      from .speak import *

      使用

      >>> from lucky_package import * # 导入lucky_package里speak包 >>> name # 获取name的值 zutuanxue_com
    • 注意

      不建议这样使用方式

需要 登录 才可以提问哦