• Python模块竟然如此简单?


    使用python时,常常会涉及到库的调用,这就需要掌握模块的基本知识。本文分为如下几个部分

    • 概念说明
    • 模块的简单调用
    • 包的导入
    • 特殊的__init__.py文件
    • 导入模块的搜索路径
    • __all__
    • 绝对引用与相对引用
    • import运行本质
    • if __name__ == '__main__'

    概念说明

    这里厘清python中模块、库、包之间的概念差异

    • 模块(module)其实就是py文件,里面定义了一些函数、类、变量等
    • 包(package)是多个模块的聚合体形成的文件夹,里面可以是多个py文件,也可以嵌套文件夹
    • 库是参考其他编程语言的说法,是指完成一定功能的代码集合,在python中的形式就是模块和包

    模块的简单调用

    比如我们有一个trymodule的文件夹,里面有一个first.py文件,文件中的内容如下

    a = 1
    def myfun(s):
        print(s + 1)

    trymodule的文件夹下打开命令行窗口(按住shift单击鼠标右键,选择“在此处打开命令窗口”),输入python进入命令行交互模式

    >>> import first
    >>> a
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'a' is not defined
    >>> first.a
    1
    >>> first.myfun(2)
    3

    所以说first.py文件就是一个模块,可以用import导入,里面变量都要用first.前缀来引用,如果想不使用这个前缀可以这样

    >>> from first import a
    >>> a
    1

    其他用法如下

    # 重命名
    >>> from first import myfun as addone
    >>> addone(4)
    5
    # 导入模块中全部变量
    >>> from first import *
    >>> myfun(2)
    3
    # 一次导入多个变量
    >>> from first import a, myfun
    >>> a
    1

    很多人学习python,不知道从何学起。
    很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
    很多已经做案例的人,却不知道如何去学习更加高深的知识。
    那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
    QQ群:609616831


    包的导入

    在trymodule文件夹中新建folder1文件夹,我们想让folder1文件夹成为一个包。文件夹里新建abcd.py文件,文件中内容如下

    b = 2
    class Myclass:
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def get_info(self):
            print('my name is {name} and age is {age}'.format(name = self.name, age = self.age))

    此时在folder1文件夹中新建一个__init__.py文件,否则程序会将这个文件夹当成普通文件夹来处理而不是一个包。这个__init__.py文件中可以什么都不填。

    此时文件结构如下

    trymodule
    │   first.py
    ├───folder1
    │   │   abcd.py
    │   │   __init__.py

    我们还是在trymodule文件夹下打开命令行,进入python交互模式

    我们来看一下下面几种导入方式

    >>> import folder1
    >>> folder1.abcd.b
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: module 'folder1' has no attribute 'abcd'
    >>> from folder1 import abcd
    >>> bob = abcd.Myclass(name = 'Bob', age = 20)
    >>> bob.name
    'Bob'
    >>> bob.get_info()
    my name is Bob and age is 20
    >>> from folder1.abcd import b
    >>> b
    2
    >>> import folder1.abcd
    >>> abcd.b
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'abcd' is not defined
    >>> folder1.abcd.b
    2
    >>> import folder1.abcd as aa
    >>> aa.b
    2

    注意:

    • 只是导入包不能随便使用其中的模块,要导入到具体模块或者变量的层次
    • 文件夹与文件之间可以用.也可以用from import格式,而文件与里面的变量之间只能用from import格式,即不能import folder1.abcd.b

    特殊的__init__.py文件

    __init__.py文件其实是一个特殊的文件,它相当于名为folder1模块,即如果使用import folder1则可以调用在__init__.py文件文件中定义的变量。

    __init__.py文件编写如下

    from folder1.abcd import b
    c = 3

    在trymodule文件夹下打开命令行,进入python交互模式

    >>> import folder1
    >>> folder1.c
    3
    >>> folder1.b
    2
    >>> from folder1 import b
    >>> b
    2

    对比之前的from folder1.abcd import b,使用__init__.py文件可以将常用的一些变量导入以方便调用。

    另外需要注意两点

    • __init__.py文件编写时,如果要导入其他模块中的变量,即使__init__.py文件和abcd.py文件在同一个文件夹下,也不能from abcd import b,要从abcd文件从哪里来的开始写,即从包的名称开始。
    • folder1文件夹里的嵌套文件夹内不需要新建__init__.py文件即可像模块一样调用,但是一般还是要新建这个文件,可以方便地导入常用变量。

    导入模块的搜索路径

    import hello时,python会搜寻hello.py文件,搜索顺序如下

    • 首先搜寻内置模块是否有hello(所以我们定义的模块名不要和内置模块相同)
    • 如果内置模块没有,则看下面这些目录里有没有
    >>> import sys
    >>> sys.path
    ['', 'C:\Program Files\Anaconda3\python35.zip', 'C:\Program Files\Anaconda3\DLLs', 'C:\Program Files\Anaconda3\lib', 'C:\Program Files\Anaconda3', 'C:\Program Files\Anaconda3\lib\site-packages', 'C:\Program Files\Anaconda3\lib\site-packages\Sphinx-1.4.6-py3.5.egg', 'C:\Program Files\Anaconda3\lib\site-packages\snownlp-0.12.3-py3.5.egg', 'C:\Program Files\Anaconda3\lib\site-packages\win32', 'C:\Program Files\Anaconda3\lib\site-packages\win32\lib', 'C:\Program Files\Anaconda3\lib\site-packages\Pythonwin', 'C:\Program Files\Anaconda3\lib\site-packages\setuptools-27.2.0-py3.5.egg']

    其中第一个''表示当前的工作路径,我们可以看出安装的第三方包所在路径('C:\Program Files\Anaconda3\lib\site-packages')也在这个列表之中,所以无论工作路径在哪里,都能搜寻到这些包。

    如果想添加搜索路径,可以参考这篇文章

    __all__

    首先要明确,import *的方式无法导入以下划线开头的变量名

    __init__.py文件内容更改如下

    from folder1.abcd import b
    c = 3
    _e = 4

    python交互模式下

    >>> from folder1 import *
    >>> c
    3
    >>> _e
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name '_e' is not defined

    而如果指定导入是可以的

    >>> from folder1 import c
    >>> c
    3
    >>> from folder1 import _e
    >>> _e
    4

    如果定义了__all__,则import *就可以导入下划线开头的变量

    __init__.py文件内容更改如下

    from folder1.abcd import b
    __all__ = ['c', '_e']
    c = b + 1
    _e = 4

    python交互模式下

    >>> from folder1 import *
    >>> b
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'b' is not defined
    >>> c
    3
    >>> _e
    4

    可见import *只会导入__all__中指定的变量,无论是否以下划线开头。这样限制可以防止import *命令导入太多变量污染命名空间,过滤掉一些中间变量如b

    绝对引用与相对引用

    python中的import分为绝对引用和相对引用两种。它们之间的差异在于,引用模块时 定位被引用模块位置 的方式不同

    • 绝对引用是明确指定最高级文件(夹),文件之间用.连接,依次下来达到待引用模块。我们上面的所有用法都属于绝对引用。
    • 而相对引用是 指定待引用模块与当前文件的相对位置,.表示上一级文件

    在这样的文件结构下

    trymodule
    │   first.py
    ├───folder1
    │   │   abcd.py
    │   │   __init__.py

    编写__init__.py文件,其中要引用abcd.py文件中的变量

    • 绝对引用是from folder1.abcd import b
    • 相对引用是from .abcd import b

    相对引用中,.是指父文件(也有from . import xxx的用法),.xxx是指同一层文件,..xxx则是与父文件夹同级的xxx文件(多一个.表示多往上一层)

    一般用哪个呢?

    python3之后官方推荐用绝对引用的方式,只有当模块中文件关系非常复杂时相对引用才会有优势。

    import运行本质

    使用import语句,要明确两件事

    (1)执行导入模块命令时,会首先检查待导入的模块是否在当前已有模块之中,如果有则跳过import。因此模块之间相互引用不会导致无限循环。

    查看当前已导入模块使用下面方法

    import sys
    sys.modules

    得到结果是一个字典,键是模块名,值是文件所在路径

    (2)import语句与文件执行

    在这样的文件结构下

    trymodule
    │   first.py
    ├───folder1
    │   │   abcd.py
    │   │   __init__.py

    folder1是一个package,abcd是一个module

    • import folder1 只是导入package,相当于执行__init__.py文件
    • from folder import abcd则执行了__init__.py文件文件与abcd.py文件
    • from folder1.abcd import b其实也执行了__init__.py文件文件与abcd.py文件

    (要知道执行了什么,可以在这些文件之中添加print语句,看是否打印出结果)

    知道这个执行原理,可以更好理解前面得到的一些结论

    • 首先是在__init__.py文件中什么都没有的情况下,import folder1无法调用abcd模块中的变量,是因为相当与运行了一个空文件,没有将整个包导入工作空间
    • abcd模块中定义了print语句后,import两次,只有第一次会print出值,说明第二次检查出模块已在导入之列,忽略了这条import命令

    更多运行细节可以参考这篇文章

    if __name__ == '__main__'

    我们经常会在别人的代码中发现if __name__ == '__main__',为了理解它的作用,我们来看下面的例子

    在folder1文件夹下新建new.py文件,里面内容为

    print(__name__)

    在folder1文件夹下打开命令行,输入

    python new.py

    返回结果是__main__

    在trymodule文件夹下打开命令行,进入python交互模式

    >>> from folder1 import new
    folder1.new
    >>> print(__name__)
    __main__
    >>> print(new.__name__)
    folder1.new

    上面测试结果说明直接运行文件和import文件是有差异的,差异在于二者的__name__变量不同。__name__变量是一个特殊的变量,每个py文件运行时都会对应一个__name__变量,即使在交互模式下也可以查看这个变量值。

    所以if __name__ == '__main__'的作用就很好理解了,即import时不执行下面的代码,只有在直接执行这个文件时才运行之后的代码。这算是一种约定俗成的写法,如果不怕文件被import,可以不用这个。

    在这里还是要推荐下我自己建的Python学习群:609616831,群里都是学Python的,如果你想学或者正在学习Python ,欢迎你加入,大家都是软件开发党,不定期分享干货(只有Python软件开发相关的),包括我自己整理的一份2020最新的Python进阶资料和零基础教学,欢迎进阶中和对Python感兴趣的小伙伴加入!

  • 相关阅读:
    null和undefined的区别
    减少页面加载时间的方法
    html5有哪些新特性、移除了那些元素?
    cookies,sessionStorage 和 localStorage 的区别
    小程序页面
    快速保存网页图片的工具
    Flex 布局教程
    第一阶段:Python开发基础 day08 Python基础语法入门--列表元组字典集合类型的内置方法
    第一阶段:Python开发基础 day08 数据类型的内置方法 课后作业
    python学习第一周知识内容回顾与小结
  • 原文地址:https://www.cnblogs.com/python-miao/p/14260750.html
Copyright © 2020-2023  润新知