Python学习笔记5:模块

Python学习笔记5:模块

这篇博文是之前的博文《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/ 请尊重其他人的劳动成功,转载请注明。
原文地址:https://www.cnblogs.com/Moon-Face/p/14523742.html