zoukankan      html  css  js  c++  java
  • python学习之模块

    python学习之模块

    模块

    基本概念

    在python中,模块是相对于命令行执行的一个概念。如果我们抛开IDE,在cmd下调用python并使用命令行执行命令,就会存在一个问题,前边命令创建的变量在后续执行中无法保存和使用。而模块就是为此存在,简单的说模块就是一组变量、函数、类的集合,到这里我们就可以发现,其实单个的python源代码文件就是一个模块。

    #test.py
    def test():
        print("this is a module test")
    a=test
    a()
    print(dir())
    print(__name__)
    

    输出

    this is a module test
    ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'test']
    __main__

    上边代码中dir()的作用是输出当前已注册的命名,可以简单的理解为当前可以使用的变量、函数、类等。__name__是当前的模块名,如果__name__="__main__“则表示当前模块是这次执行的入口,也就是说这次是由python程序直接执行test.py,而非其它模块引用。

    模块引用

    当然,一个模块是可以引入另一个模块的,我们可以在同目录下创建另一个模块:

    #test2.py
    print("this is module test2")
    def test2Function():
        print("this is a function in module test2")
    print("this is test2 module name:"+__name__)
    

    我们可以使用import moduleName的方式引入test2模块:

    #test.py
    import test2
    def test():
        print("this is a module test")
    a=test
    a()
    print(dir())
    print(__name__)
    test2.test2Function()
    

    输出

    this is module test2
    this is test2 module name:test2
    this is a module test
    ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'test', 'test2']
    __main__
    this is a function in module test2

    这样在test中就可以执行test2的函数了,import moduleName的本质就是把moduleName加入当前命名空间,可以在当前直接使用moduleName这个模块。但现在还有个问题,我们注意到test2中函数体外的print也直接输出了,这表明一旦我们使用了import moduleName,相应模块中没包在函数体或者类中的程序都将执行,这在我们一些情况下是不希望的结果。这里需要用到__name__,我们可以这样:

    #test2.py
    if __name__=="__main__":
        print("this is module test2")
    def test2Function():
        print("this is a function in module test2")
    if __name__=="__main__":
        print("this is test2 module name:"+__name__)
    

    这样再执行test时候就不会显示this is module test2了,如果直接执行test2,依然会显示。这就是前边所说的,利用__name__区分当前模块是不是程序入口。

    此外,我们可以使用from moduleName import funcName的方式直接引用某个模块的单个函数。

    #test.py
    from test2 import test2Function
    print(dir())
    test2Function()
    

    输出

    ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'test2Function']
    this is a function in module test2

    可以看到,当前命名空间中没有test2,而是直接加载了test2Function,调用的时候自然不需要模块名,可以直接使用test2Function

    如果要一次引用单个模块的多个函数,可以这样:from moduleName import func1,func2...,也可以from moduleName import *。但是后者要谨慎使用,因为可能污染当前的命名空间。

    包是常见的代码组织方式,python同样支持。现在假设我们有一组时间工具函数,组织成一个包。工作目录结构为:

    • time_tools
      • __init__.py
      • date.py
      • time.py
    • test.py

    初始化文件

    包中的__init__.py文件是包的初始化文件,当包被引用的时候会执行。包中之所以会存在这个文件,主要有两点用途。

    1. 区分包和普通的文件夹,避免编译器对无效文件目录的检索。
    2. 可以在包所属的__init__.py文件中编写引入包时需要的初始化逻辑,或者定义整个包共享的工具方法等。
    #__init__.py
    #比较两个时间戳大小
    def compareTimestamp(time1,time2):
        if time1>time2:
            return 1
        elif time1==time2:
            return 0
        else:
            return -1
    
    #date.py
    #显示当前日期
    def showNowDate():
        print("now date is X year X month X date")
    #判断今天是否工作日
    def isWorkDay():
        return True
    
    #time.py
    #显示当前时间
    def showNowTime():
        print("now time is XX:XX:XX")
    #获取当前时间戳
    def getTimestamp():
        return "time stamp"
    

    包引用

    我们可以使用import package1.package2.module的方式来引入其它包的模块:

    #test.py
    import time_tools.date
    import time_tools.time
    time_tools.date.showNowDate()
    time_tools.time.showNowTime()
    

    输出

    now date is X year X month X date
    now time is XX:XX:XX

    但这样的话每次使用都要使用package1.package2.module.func()这样,如果要更方便的使用模块,可以使用from package1.package2 import module的方式:

    #test.py
    from time_tools import time
    from time_tools import date
    date.showNowDate()
    time.showNowTime()
    

    但同样的,这样做要注意污染命名空间的问题,如果遇到了,或许可以这样:

    #test.py
    import time_tools.date
    import time_tools.time
    timeToosDate=time_tools.date
    timeToosTime=time_tools.time
    timeToosDate.showNowDate()
    timeToosTime.showNowTime()
    

    与使用from module import *类似,我们也可以使用from pack1.pack2 import *一次性引用包下边所有的模块。比如:

    #test.py
    from time_tools import *
    print(compareTimestamp(111,222))
    time.showNowTime()
    

    输出

    -1
    Traceback (most recent call last):
    File "d:workspacepython est.py", line 4, in
    time.showNowTime()
    NameError: name 'time' is not defined

    可以看到__init__.py文件中的函数可以正常调用,但对time模块的调用报错,并没有正常引用。

    这涉及另一个问题。每当我们引入一个模块,编译器就会去文件目录查找,但如果是使用*一次性引入某个包下边的所有模块,那就是编译器直接读取文件目录下的所有文件,然后加载。这看似没有问题,但在windows下有个致命问题——windows的文件目录是不区分大小写的。这就导致python的编译器不知道一个模块echo.py是要加载为echo还是ECHO甚至Echo。为了解决这个问题,在使用*加载包时候,需要在包的初始化文件中显示地指定包下边的模块名,比如:

    #__init__.py
    #比较两个时间戳大小
    __all__=["date","time"]
    def compareTimestamp(time1,time2):
        if time1>time2:
            return 1
        elif time1==time2:
            return 0
        else:
            return -1
    

    这样就可以正常加载了:

    #test.py
    from time_tools import *
    # print(compareTimestamp(111,222))
    time.showNowTime()
    

    输出

    now time is XX:XX:XX

    此时包time_tools本身并没有被加载,所以compareTimestamp无法使用

    参考资料

    https://www.runoob.com/python3/python3-module.html

    标准库

    标准库是python自带的模块,已经封装了一些常用功能。

    random

    random模块提供随机数的相关功能:

    import random
    print(random.random())
    #生成一个随机整数
    print(random.randint(1,10))
    #在一个list中随机选定多个
    print(random.sample([1,2,3,4,5,6],3))
    

    输出

    0.7140202136447632
    2
    [1, 6, 5]

    sys

    sys模块可以输出一些python系统信息,比如主程序的输入参数,编译器的检索路径等:

    import sys
    print(sys.argv)
    print(sys.path)
    sys.path.append("D:\worksapce\python\time_tools")
    print(sys.path)
    

    sys.argv会返回主程序输入参数,sys.path则是一个包含了编译器检索用的目录列表,而可以通过sys.path.append()的方式追加目录。

    第三方模块

    pip的第三方模块存放在pypi.org,检索相当方便,并不会如同github一般经常性抽风。

    第三方模块的安装和管理工具是pip,经常使用的命令有:

    pip install moduleName
    pip uninstall moduelName
    pip list #列出已安装模块
    

    you-get

    下面用一个视频下载模块you-get举例:

    在cmd下输入

    pip install you-get
    

    等待片刻后就安装好了,接下来可以试着直接下载视频:

    you-get https://www.bilibili.com/video/BV1y7411m7Xj
    

    需要注意的是you-get.exe的所在的目录需要加入系统环境变量,而且电脑要重启生效后才能在cmd下直接调用you-get

    当然,pip安装的不仅仅是可执行程序,还安装了python源码,可以直接在python中调用:

    from you_get import common
    common.any_download(url="https://www.bilibili.com/video/BV1y7411m7Xj",output_dir="d:\download",merge=True,info_only=False,stream_id="flv")
    

    输出

    site: Bilibili
    title: 你这么可爱 可惜不会谈恋爱
    stream:
    - format: flv
    container: flv
    quality: 高清 1080P
    size: 17.7 MiB (18576369 bytes)
    # download-with: you-get --format=flv [URL]

    Downloading 你这么可爱 可惜不会谈恋爱.flv ...
    100% ( 17.7/ 17.7MB) ├████████████████████████████████████████┤[1/1] 7 MB/s

    Skipping captions or danmaku.

    • 我比较迷惑的是pypi官网并没有该模块的python调用文档,不知道是为什么。

    • 关于第三方库的更多内容可以阅读简明教程

    本篇文章首发自魔芋红茶的博客https://www.cnblogs.com/Moon-Face/ 请尊重其他人的劳动成功,转载请注明。
  • 相关阅读:
    my first android test
    VVVVVVVVVV
    my first android test
    my first android test
    my first android test
    ini文件
    ZZZZ
    Standard Exception Classes in Python 1.5
    Python Module of the Week Python Module of the Week
    my first android test
  • 原文地址:https://www.cnblogs.com/Moon-Face/p/14460098.html
Copyright © 2011-2022 走看看