回来了

很久没有更新博客了,上了研究生之后,科研任务蛮重的,还要兼顾学习任务,有时候想写写博客记录记录学习内容,总结总结学习心得什么的,都难有时间。

本科的时候博客大部分内容偏向于实践,尤其是Web方面的实践内容,因为当时想着好找工作,又比较喜欢就自己有事没事钻研学习。现在读研了,不太想继续搞前端了,目前正在努力的方向是大数据、数据分析、数据挖掘之类的方向(属于算法方向,对我来说还是比较困难,不过没关系,把时间花在做上就好了)。所以前端、Web相关的博客可能会减少了,但是实践风格依然不变,我还是喜欢做做东西比较实在,当然,也会写一些偏理论的文章,毕竟搞研究嘛,理论还是得有些积累。

使用matplotlib遇到了问题

matplotlib是python中用来对标matlab的一个绘图库,可以方便的画各种科学计算图。最近有科研需求需要用到matplotlib库,但是在导入使用matplotlib库是遇到了比较诡异的问题。

官方文档中给出的引入matplotlib的方式如下:

import matplotlib.pyplot as plt

这样本身是没有什么问题的,plt可以正常访问pyplot模块中的各种接口。但是当我尝试想下面这样引入时,遇到了 AttributeError: module 'matplotlib' has no attribute 'pyplot' 的问题。

import matplotlib
plt = matplotlib.pyplot

这是为什么呢?我又尝试如下引用方式,并对两次引用的pyplot比较,看是否是同一个对象:

import matplotlib.pyplot as plt
import matplotlib as mpl

if plt is mpl.pyplot:
    print('True')
else:
    print('False')

神奇的是,这一次mpl.pyplot没有报错,且输出为True。也就是说,这一次pyplotmatplotlib命名空间中存在了,且就是我们第一行导入的那个pyplot。这是为什么呢?

正解

为了搞清楚其中的原理,我特地去看了看matplotlib源码包。想知道matplotlib源码放在哪里?在python交互式模式下输入以下代码即可知道位置:

>>> import matplotlib
>>> matplotlib
<module 'matplotlib' from 'C:\\Users\\angelavor\\anaconda3\\envs\\ML\\lib\\site-packages\\matplotlib\\__init__.py'>

转到matplotlib源码相应位置,可以看到其源码结构如下:
在这里插入图片描述
整个源码还是比较庞大的,我们只需要看几个关键文件及其结构:

matplotlib
	|_______ axes
	|_______ __init__.py
	|_______ ......
	|_______ pyplot.py

首先明确两个概念——包和模块。包是python组织模块的一种方式,简单来说,包就是文件夹,包中放许多模块。模块是python组织源码的一种方式,简单来说,模块就是一个py文件。所以这里,matplotlibpyplot的关系就是包与其模块的关系。

import的语句是如何识别出包和模块的呢?关键就是 __init__.py文件,有关python模块化中__init__.py的作用这里有两篇博客写的很好(链接通道1链接通道2),可以参考。

简单来说,一个文件夹下只有存在__init__.py才能被识别为一个可导入的python包。导入包其实是导入此包下的__init__.py模块。所以,__init__.py也起到初始化包的作用,事实上,导入包的时候会执行此脚本,初始化参数并加载一些需要的模块。

默认情况下,__init__.py可以什么也不写,只起到标识python包的作用,但是这个时候仅仅导入包是什么都做不了的,因为没有任何模块预加载。这里pyplot模块之所以没能通过引入matplotlib来引入,是因为其__init__.py中根本就没有加载引入pyplot模块 !!!

又因为pyplot是属于matplotlib命名空间下的,因此一旦显式导入模块,它就自动加入matplotlib命名空间下了。这也就解释了开头出现的比较诡异的问题。

总结一下

  1. 直接引入matplotlib包是不能引入pyplot模块的

  2. 官方推荐直接引入matplotlib.pyplot,原因其实可以在__init__.py源码中的文档注释找到答案。我这里引用一下这些注释。

    A procedural interface is provided by the companion pyplot module,which may be imported directly, e.g.::
    import matplotlib.pyplot as plt

    For the most part, direct use of the object-oriented library is encouraged when
    programming; pyplot is primarily for working interactively. The exceptions are
    the pyplot functions .pyplot.figure, .pyplot.subplot, .pyplot.subplots,
    and .pyplot.savefig, which can greatly simplify scripting.

    翻译一下,就是pyplot模块里整合了matplotlib库里的画图接口。大部分情况下,在编写程序中推荐使用面向对象的方式;但是在交互式模式下,可以通过pyplot函数快速的上手绘图。

  3. 如果想避免出现找不到module的问题,可以把matplotlibmatplotlib.pyplot都引入,想下面这样即可:

    import matplotlib.pyplot as plt
    import matplotlib as mpl
    

收工!睡觉~

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐