红茶的个人站点

  • 首页
  • 专栏
  • 开发工具
  • 其它
  • 隐私政策
Awalon
Talk is cheap,show me the code.
  1. 首页
  2. 编程语言
  3. Python
  4. 正文

Python学习笔记5:模块

2021年3月19日 309点热度 0人点赞 0条评论

模块

这篇博文是之前的博文《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
# ['__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
# ['__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_v2 import test2Function
print(dir())
test2Function()
# ['__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()
# now date is X year X month X date
# now time is XX:XX:XX

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

#test.py
import time_tools.date
import time_tools.time
timeToosDate=time_tools.date
timeToosTime=time_tools.time
timeToosDate.showNowDate()
timeToosTime.showNowTime()
# now date is X year X month X date
# now time is XX:XX:XX

与使用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:\workspace\python\python-learning-notes\note5\test.py", line 4, in <module>
#     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.9078117032490299
# 9
# [3, 2, 1]

sys

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

import sys
print(sys.argv)
print(sys.path)
sys.path.append("D:\\worksapce\\python\\time_tools")
print(sys.path)
# ['D:\\workspace\\python\\python-learning-notes\\note5\\test.py']
# ['D:\\workspace\\python\\python-learning-notes\\note5', 'D:\\software\\Coding\\Python\\python39.zip', 'D:\\software\\Coding\\Python\\DLLs', 'D:\\software\\Coding\\Python\\lib', 'D:\\software\\Coding\\Python', 'C:\\Users\\70748\\AppData\\Roaming\\Python\\Python39\\site-packages', 'D:\\software\\Coding\\Python\\lib\\site-packages', 'D:\\software\\Coding\\Python\\lib\\site-packages\\you_get-0.4.1500-py3.9.egg']
# ['D:\\workspace\\python\\python-learning-notes\\note5', 'D:\\software\\Coding\\Python\\python39.zip', 'D:\\software\\Coding\\Python\\DLLs', 'D:\\software\\Coding\\Python\\lib', 'D:\\software\\Coding\\Python', 'C:\\Users\\70748\\AppData\\Roaming\\Python\\Python39\\site-packages', 'D:\\software\\Coding\\Python\\lib\\site-packages', 'D:\\software\\Coding\\Python\\lib\\site-packages\\you_get-0.4.1500-py3.9.egg', 'D:\\worksapce\\python\\time_tools']

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调用文档,不知道是为什么。

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

  • 关于如何自己开发模块,可以阅读Python学习笔记番外:构建你自己的第三方模块。

image-20210606174712139

本系列文章的代码都存放在Github项目:python-learning-notes。

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: Python 模块
最后更新:2021年6月6日

魔芋红茶

加一点PHP,加一点Go,加一点Python......

点赞
< 上一篇
下一篇 >

文章评论

取消回复

*

code

COPYRIGHT © 2021 icexmoon.cn. ALL RIGHTS RESERVED.
本网站由提供CDN加速/云存储服务

Theme Kratos Made By Seaton Jiang

宁ICP备2021001508号

宁公网安备64040202000141号