• Python包基本概念

    背景

    本文意在将python基础基础进行简单的归纳和介绍,属于个人总结,并无技术含量,请老司机绕道而行。

    内容

    什么是python包

    其实我们在将模块的时候已经解释过这个了,这里再次阐述一下:Python引入了按目录来组织模块的方法,称为包(Package),来避免模块名冲突,比如在项目合作中与其他人写的模块名冲突,这个可能性其实挺高的,比如我写了一个runsql.py,他也写了一个runsql.py。

    引入了包以后,只要顶层的包名不与别人冲突,那所有模块都不会与别人冲突。每一个包目录下面都会有一个__init__.py的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个python包。__init__.py 可以是空文件,也可以有Python代码,因为__init__.py 本身就是一个模块。

    %e5%b1%8f%e5%b9%95%e5%bf%ab%e7%85%a7-2017-05-07-%e4%b8%8b%e5%8d%885-24-18

    Python项目下的包管理的正确引用方式

    假设我有如下Python项目:

    如上,假设package是我们的一个python项目,我想让subpackage2中的foo2来import subpackage1中的foo1,上面的这种方式直接运行肯定是不行的:

    方式1:修改PYTHONPATH系统环境变量:

    方式2: 使用sys.path.append的方式

    方式3: 使用python -m的方式

    首先,解释一下python -m 的作用, -m参数会把你输入命令的目录(也就是当前路径),放到sys.path。 我们来举个例子。

    一般情况下,我不用-m参数,当我正常的指定脚本执行时,它默认会将目标脚本(foo2.py)所在的目录(subpackage2)的绝对路径加入 sys.path 中:

    如果我加上-m以后,则会将我指定的路径目录package作为一个模块导入sys.path中:

    也就是说,如果用-m参数的形式的话,我可以在整个项目的应用中直接按包路径来import,也就是说,即使你想在app.py中导入subsubpackage11下的foo11,我也可以直接按照包路径导入:

    哇,是不是感觉好清晰啊。

    但是,凡事有利有弊吧,如果你想用 -m 的这种方式,那么你只能在package所在的目录下运行 python -m 命令。


    上面的三个方法都可以实现python项目中的包模块导入,各有利弊,但是个人比较偏向于第3种吧,因为在代码中看起来更清晰一些。

    • 如果你用PYTHONPATH,那么当有多个项目时,你需要把每个项目的根目录都加入到PYTHONPATH中,会使得PYTHONPATH变得十分臃肿
    • 如果你使用sys.path,由于文件夹是动态添加的,所以当你使用相对路径的时候,实际路径会十分依赖于你的入口函数,当入口函数改变很可能就会导致代码无法运行
    • 如果你使用绝对路径,将你的代码在其他机器上运行的时候需要重新配置这些变量,十分麻烦
    import * 与 __all__

    当你在package项目中执行  from subpackage1 import * 会发生什么呢 ?

    理想情况下,我们希望程序会在指定的subpackage1包文件中,找到所有子模块, 并把它们全部导入. 那么真的是这样吗?

    由上面的测试我们看到, import * 貌似并不会向我们期待的那样将对应包下面对应的模块全部导入。

    这里一定要注意不要和模块的导入混为一谈,我们上面测试的包的导入,from package.subpackage1 import * 这个import语句中import的对象是一个包,如果是一个模块,那是可以直接调用模块里的内容的,比如:

    哦,终于明白了,那么如果我就想让 import * 也可以导入包中的模块怎么办呢 ? 当然也是有办法的,就利用我们的__all__ 变量,只需要在对应包的的 __init__.py 代码定义了一个名为 __all__ 的列表,那么当遇到 from package import * 时, 这个 __all__ 就被用来作为导入的模块名字的列表。

    但是这样可能有点麻烦的是你需要不断的维护这个__all__列表,所以个人建议,在使用 import 时,最好能指定具体的模块,而尽量避免使用 import * 这种用法。

     

     

    参考

    https://docs.python.org/3/tutorial/modules.html

    http://blog.csdn.net/luo123n/article/details/49849649

     

  • Python模块基本概念

    背景

    本文意在将python基础基础进行简单的归纳和介绍,属于个人总结,并无技术含量,请老司机绕道而行。

    内容

    什么是python模块

    Python 模块(Module),是一个以 .py 结尾的Python文件,包含了 Python 对象定义和Python语句。在一个模块中, 模块的名字 (一个字符串) 可以通过全局变量 __name__ 得到。

    例如, 在当前目录下创建一个名为 fibo.py 的文件, 并输入以下内容:

    现在打开 Python 解释器并通过以下命令导入这个模块:

    python模块的存在意义
    • 模块让你能够有逻辑地组织你的 Python 代码段。模块最大的好处是大大提高了代码的可维护性。
    • 编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括Python内置的模块和来自第三方的模块。
    • 避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。但是也要注意,尽量不要与内置函数名字冲突。

    等等,上面的第3点说到模块可以避免函数名和变量名冲突,这个我可以理解,那如果模块名冲突怎么办? 比如在项目合作中与其他人写的模块名冲突了。这个可能性挺高的啊,比如我写了一个runsql.py,他也写了一个runsql.py。

    Python又引入了按目录来组织模块的方法,称为包(Package)。引入了包以后,只要顶层的包名不与别人冲突,那所有模块都不会与别人冲突。每一个包目录下面都会有一个__init__.py的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个python包。__init__.py 可以是空文件,也可以有Python代码,因为__init__.py 本身就是一个模块。

    %e5%b1%8f%e5%b9%95%e5%bf%ab%e7%85%a7-2017-05-07-%e4%b8%8b%e5%8d%885-24-18

    模块的引入

    模块定义好后,我们可以使用 import 语句来引入模块,语法如下:

    比如要引用模块 math,就可以在文件最开始的地方用 import math 来引入。在调用 math 模块中的函数时,必须这样引用:

    import语句还有一种不同用法, 它可以直接把一个模块内(函式,变量)名称导入当前模块符号表里. 例如:

    这样不会导入相应的模块名 (在这个例子里, fibo并没有被定义).

    当然,我们也可以一次性导入模块中所有的名字定义:

    这样可以导入除以下划线开头 (_) 的所有名字. 多数情况中, Python 程序员不使用这个窍门, 因为它导入了一些未知的名字到解释器里, 因此可能会意外重载一些你已经定义的东西.

    注意: 在一般的实践中, 导入 * 是不好的, 因为它常常产生难以阅读的代码. 然而, 在一个交互式会话里使用它可以节省键入.

    模块的属性

    模块有一些内置属性,用于完成特定的任务,如__name__、__doc__。

    在模块内部,模块名存储在全局变量__name__中,是一个string,可以直接在module中通过__name__引用到module name。如果当前程序正在被使用,__name__的值为“__main__”,否则为module name ,通常给每个模块都添加一个条件语句,用于单独测试该模块的功能。如下:

    yy

    当我去运行 b.py 的时候结果如下:

    那么这里有一个问题,这个b.py是从哪里搜索a.py的呢?  我这个a.py 应该放在哪里才可以被他引用呢?

    模块的查找路径

    当我们试图加载一个模块时,Python会在指定的路径下搜索对应的.py文件,如果找不到,就会报错:

    那么Python导入一个模块时,会从哪里寻找呢 ?Python在sys.path里面记录的所有目录中搜索对应的模块。而sys.path 主要包含如下的搜索路径:

    1. Python首先查找当前路径
    2. 如果不在当前目录,Python 则搜索在 shell 变量 PYTHONPATH 下的每个目录
    3. 如果都找不到,Python会查看默认路径。默认路径一般为安装目录下的 lib/python目录

    我们来看看:

    如果我们要添加自己的搜索目录,有两种方法:

    一是直接修改 sys.path ,添加要搜索的目录:

    这种方法是在运行时修改,运行结束后失效。

    第二种方法是设置环境变量 PYTHONPATH ,该环境变量的内容会被自动添加到模块搜索路径中。设置方式与设置Path环境变量类似。注意只需要添加你自己的搜索路径,Python自己本身的搜索路径不受影响。

    模块的作用域

    在一个模块中,我们可能会定义很多函数和变量,但有的函数和变量我们希望给别人使用,有的函数和变量我们希望仅仅在模块内部使用。在Python中,是通过_前缀来实现的。

    正常的函数和变量名是公开的(public),可以被直接引用。

    类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如__author__  __name__ 就是特殊变量,我们自己的变量一般不要用这种变量名;

    类似 _xxx __xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如 _abc  __abc等;

    之所以我们说,private函数和变量“不应该”被直接引用,而不是“不能”被直接引用,是因为Python并没有一种方法可以完全限制访问private函数或变量,但是,从编程习惯上不应该引用private函数或变量。

    private函数或变量不应该被别人引用,那它们有什么用呢?请看例子:

    我们在模块里公开greeting函数,而把内部逻辑用private函数隐藏起来了,这样,调用greeting函数不用关心内部的private函数细节,这也是一种非常有用的代码封装和抽象的方法,即:

    外部不需要引用的函数全部定义成private,只有外部需要引用的函数才定义为public。

    还有一个问题,加入当我引用别的模块中的函数或变量与本模块的产生冲突时,会怎样呢 ? 比如:

    则运行结果如下:

    但如果我将b修改为如下:

    则运行结果就不一致了:

    模块的dir() 函式

    内建函式dir() 用于找出一个模块里定义了哪些名字. 它返回一个有序字串列表:

    但是貌似 dir() 并不列出内建函式和变量的名字. 如果你真心想看一下, 可以直接查询标准模块builtins

    python模块的安装

    在Python中,安装第三方模块,是通过setuptools这个工具完成的。Python有两个封装了setuptools的包管理工具easy_install 和 pip。目前官方推荐使用 pip。在Python2.7的安装包中,easy_install.py是默认安装的,而pip需要我们手动安装。

    pip安装的模块默认放在了对应的python安装路径的 lib/python/site-packages底下。

    详情一定要参考官方网址,详细简洁:https://pypi.python.org/pypi/pip

    pip的安装

    如果你安装的版本在 Python 2 >=2.7.9 or Python 3 >=3.4 ,那么你的python已经自带pip了,但是你可能需要升级。但是如果你使用virtualenv or pyvenv. 则默认都会安装pip。

    Installing with get-pip.py

    在哪找第三方包?

    在安装第三方包之前,你首先要找到他们。以下是几种方法:

    1. 你的系统包管理器中的发行版专用包。
    2. Python Package Index (or PyPI)
    3. 大量的源代码服务器,例如 LaunchpadGitHubBitBucket 等
  • python环境基础概念

    背景

    本文意在将python基础基础进行简单的归纳和介绍,属于个人总结,并无技术含量,请老司机绕道而行。

    内容

    1. Python解释器

    当我们编写Python代码时,我们得到的是一个包含Python代码的以.py为扩展名的文本文件。要运行代码,就需要Python解释器去执行.py文件。

    由于整个Python语言从规范到解释器都是开源的,所以理论上,只要水平够高,任何人都可以编写Python解释器来执行Python代码(当然难度很大)。事实上,确实存在多种Python解释器。

    CPython

    当我们从Python官方网站下载并安装好Python 3.5后,我们就直接获得了一个官方版本的解释器:CPython。这个解释器是用C语言开发的,所以叫CPython。在命令行下运行python命令就是启动CPython解释器。

    CPython是使用最广的Python解释器。它把Python代码编译成 中间态的字节码,然后由虚拟机解释。CPython为Python包和C扩展模块提供了最大限度的兼容。如果你正在写开源的Python代码,并希望有尽可能广泛的用户,用CPython是最好的。使用依赖C扩展的包,CPython是你唯一的选择。

    所有版本的Python语言都用C实现,因为CPython是参考实现。

    IPython

    IPython是基于CPython之上的一个交互式解释器,也就是说,IPython只是在交互方式上有所增强,但是执行Python代码的功能和CPython是完全一样的。好比很多国产浏览器虽然外观不同,但内核其实都是调用了IE。

    IPython用 >>> 作为提示符,而IPython用 In [序号]:作为提示符。

    PyPy

    PyPy是另一个Python解释器,它的目标是执行速度。PyPy采用JIT技术,对Python代码进行动态编译(注意不是解释),所以可以显著提高Python代码的执行速度。

    绝大部分Python代码都可以在PyPy下运行,但是PyPy和CPython有一些是不同的,这就导致相同的Python代码在两种解释器下执行可能会有不同的结果。如果你的代码要放到PyPy下执行,就需要了解PyPy和CPython的不同点

    如果你正在寻找提高你的Python代码性能的方法,值得试一试PyPy。在一套的基准测试下, 它目前比CPython的速度快超过5倍 。PyPy支持Python 2.7。PyPy3 [2],发布的Beta版,支持Python 3。

    Jython

    Jython是运行在Java平台上的Python解释器,运行在JVM (Java Virtual Machine) 上。另外,它可以像是用Python模块一样,导入 并使用任何Java类。如果你需要与现有的Java代码库对接或者基于其他原因需要为JVM编写Python代码,那么 Jython是最好的选择。

    Jython现在支持到Python 2.7 [3]

    IronPython

    IronPython和Jython类似,只不过IronPython是运行在微软.Net平台上的Python解释器,可以直接把Python代码编译成.Net的字节码。它可以用Python和.NET framework的库,也能将Python代码暴露给给.NET框架中的其他语言。

    Python Tools for Visual Studio 直接集成了 IronPython到Visual Studio开发环境中,使之成为Windows开发者的理想选择。


    我们可能没有必要对每一种python解释器都深入研究和了解,但起码得知道有这么多python解释器,以及大概的一些功能侧重点和区别。

    2. Python IDE 编辑器

    支持Python的IDE有很多,每个人的习惯和使用方法不一样,这个可以自行选择,这里推荐几款比较常用的。

    Sublime Text

    Sublime Text 具有漂亮的用户界面和强大的功能,例如代码缩略图,Python 的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持 Windows、Linux、Mac OS X等操作系统。

    为了使用众多的插件来扩展 Sublime 的功能,我们需要安装一个叫做 Package Control 的插件管理器——这个东西你必须要手动安装。但是一旦你安装好了以后,你就可以使用 Package Control 来安装,移除或者升级所有的 ST3 插件了。

    打开sublime,然后View->Show Console菜单打开命令行,粘贴如下代码,然后回车即可:

    下面内容可能不太准确或更新,最好参考官方的这个链接:https://packagecontrol.io/installation#st3

    sublime3

    sublime2

    安装完成后,在sublime里面执行 Ctrl(command)+Shift+P 即可调出命令面板,然后输入pci即可看到我们已经拥有通过Package Control 来管理插件的能力了。

    %e5%b1%8f%e5%b9%95%e5%bf%ab%e7%85%a7-2017-05-04-%e4%b8%8a%e5%8d%8811-37-11

    我们使用它来安装一款SublimeTmpl插件,SublimeTmpl 提供了常用文件模板,新建文件时很有用。只需要在如上图中点击Package Control:Install Package,然后输入插件名称安装即可。

    那么这个插件有什么作用呢? 顾名思义,他主要在新建文件的时候可以按照我们自己制定的模板。比如:

    yy

    如上,默认情况下我们只能点击上图中用蓝色圈住的选项来新建一个空白文件。但是现在多了红色圈起来的新建选项,并且可供选择模板,比如我们选择python模板:

    %e5%b1%8f%e5%b9%95%e5%bf%ab%e7%85%a7-2017-05-04-%e4%b8%8b%e5%8d%884-05-17

    哎呦,不错呦,这样的话我就省很多事了。

    那么问题来了,我在哪里根据我自己的需求更新这些模板或者自定义新的模板呢 ?

    %e5%b1%8f%e5%b9%95%e5%bf%ab%e7%85%a7-2017-05-04-%e4%b8%8b%e5%8d%884-10-42

    如上图,我们可以在如上路径中设置和修改更新各个模板中的设置,至于新加模板和更新模板内容,请参考此插件的github官方地址耐心看,有你想要的一切

    到此为止,我们只需要在新建的文件里面写我们的python代码,然后直接执行 command + B 执行即可:

    %e5%b1%8f%e5%b9%95%e5%bf%ab%e7%85%a7-2017-05-04-%e4%b8%8b%e5%8d%884-28-13

    但是,貌似有个小问题,在上面的应用中,如果我用 command + B 执行它默认走的是系统的自带的Python2.7,如果这时候我想在command + B 之后让他默认走python3该怎么弄呢 ?

    sublime使用cmd+b的操作叫做build,在Tools -> Build System中可以看到系统默认支持的类型,包括C++、Java等各种,默认选择的是Automatic,系统会根据文件扩展名自动选择合适的Build方法。所以我们只需要新加一种build方式,并且把它设置为默认即可,如下:

    %e5%b1%8f%e5%b9%95%e5%bf%ab%e7%85%a7-2017-05-12-%e4%b8%8a%e5%8d%8811-44-46

    在打开的文件中将默认内容替换如下:

    然后保存文件名为python3.sublime-build,文件会自动保存到sublime的自定义文件夹中,mac下默认是

    重新进入刚才的Build System选项卡中,会发现下面增加了一个python3,选择该项。

    %e5%b1%8f%e5%b9%95%e5%bf%ab%e7%85%a7-2017-05-12-%e4%b8%8b%e5%8d%882-36-37

    然后再按command+B运行文件时,sublime就会用python3来运行该文件了。

    Pycharm

    Pycharm是专门的python IDE集成编辑器,功能强大,有免费版本,这里就不再详细赘述了,直接在官网上下载使用,有问题可以结合文档使用。

    官网地址:http://www.jetbrains.com/pycharm/

    3. Python安装

    目前,Python有两个版本,一个是2.x版,一个是3.x版,这两个版本是不兼容的,无论是哪个版本,都可以在官网上直接下载安装包进行安装。

    %e5%b1%8f%e5%b9%95%e5%bf%ab%e7%85%a7-2017-05-04-%e4%b8%8b%e5%8d%885-03-19

    一般情况下,Linux或Mac自带的都为Python2.6或者Python2.7版本较多,如果我们想安装python3.5可以按照如下步骤进行:

    安装完以后我们可以看到如下:

    4. Python多环境扩展管理

    现如今,Python版本众多,部分版本功能差异较大,在使用过程中经常遇到第三方库依赖的Python版本和系统Python版本不一致的情况。同时又因为系统底层调用当前版本的Python,所以不能随意更改当前版本的Python。

    比如,经常遇到这样的情况:

    • 系统自带的 Python 是 2.6,自己需要 Python 2.7 中的某些特性;
    • 系统自带的 Python 是 2.x,自己需要 Python 3.x;

    此时需要在系统中安装多个 Python,但又不能影响系统自带的 Python,即需要实现 Python 的多版本共存。于是,Python多版本管理工具应用而生,这里为大家介绍两款工具,分别是Pyenv和Virtualenv。

    两者的区别是Pyenv是对python的版本进行管理,实现不同版本间的切换和使用;而后者则通过创建虚拟环境,实现与系统环境以及其他Python环境的隔离,避免相互干扰。

    Pyenv

    Pyenv是一个简单的Python版本管理工具,以前叫做Pythonbrew。它让你能够方便的切换全局的python版本,安装多个不同的Python版本,设置独立的某个文件夹或者工程目录特异的Python版本,同时创建Python虚拟环境。所有这些操作均可以在类Unix系统的机器上(Linux和OS)不需要依赖Python本身执行,而且它工作在用户层,不需要任何sudo操作。

    github官网地址:https://github.com/pyenv/pyenv

    安装部署

    $ curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash

    安装完成后,根据提示将如下语句加入到 ~/.bashrc 中:

    注:具体可以参考github对应的Pyenv官网地址

    原理简述

    Pyenv作为Python的版本管理工具,通过改变shell的环境变量来切换不同的Python版本,已达到多版本共存的目的。该工具不支持Windows系统。具体原理如下:

    1. Pyenv安装后会在系统的 PATH 变量中插入shims路径,每次执行Python相关的可执行文件时,会优先在shims里寻找Python路径,我们来验证一下:

    如上,我们知道当我们在shell环境执行命令的时候回默认从PATH系统变量指定的路径中一一寻找,比如/usr/local/bin/目录下面就存在了很多可执行脚本。  而系统在这个命令检索的过程中遵循的是从左到右的原则,所以Pyenv机智的在PATH变量的最左边加入了shims路径。

    此时,虽然我们安装了Pyenv,并且在PATH路径中加入了shims路径,但是因为我们并没有用pyenv来安装python,所以,其实现在shims路径下面也是空的:

    OK,接下来我们就用pyenv来安装管理python版本来验证它的原理:

    OK,成功的将3.4.1 Python版本纳入pyenv管控下,这时候我们就可以根据需求来设置在下列维度使用Python版本了,主要可分为3个维度的管控:

    • pyenv shell  3.4.1   设置当前的shell环境下的Python版本为 3.4.1
    • pyenv local  3.4.1   设置当前目录下的Python应用版本为 3.4.1
    • pyenv global 3.4.1  设置当前全局环境下的Python应用版本为 3.4.1

    我们来试试呗:

    那么问题来了 !!!

    问题1: 这么多维度,使用起来会不会有些混乱呢 ? 他们的优先级是怎样的呢 ?

    答: Shell维度   —— Local 维度 —— Global维度

    我们来验证一下:

    从上面的试验中,我们发现了如下的对应关系:

    • 设置Local维度其实相当于在当前目录下创建了一个 .pyenv-version 文件,用来记录版本。
    • 设置Shell维度其实相当于将 PYENV_VERSION 系统变量记录了版本。
    • 设置Global维度相当于将 ~/.pyenv/version 文件记录了版本。

    也就是说,当我们去执行python命令时,pyenv实际上的是如何确定python版本的呢 ?

    1. 首先,查看PYENV_VERSION环境变量 ,如果有记录,则获取成功,返回。
    2. 然后,查看当前目录下的 .pyenv-version 文件,如果有记录,则获取成功,返回。
    3. 最后,查看 ~/.pyenv/version 文件,如果有记录,则获取成功,返回。

    Soga,原来如此,原来它是这样来确定和管理python版本的。

    问题2: pyenv确定了python版本以后,它是从哪里来找到对应的python解释器去执行的呢 ?

    答:从 ~/.pyenv/versions/ 路径下

    我们来验证一下:

    哦,原来我用pyenv安装的python版本是默认是安装在了这个目录地下了。

    问题3:我这样胡乱设置安装一器,会不会影响到其他系统用户的Python环境啊 ?

    答:不会

    我们来验证一下:

    这样有利有弊吧,利在于你怎么折腾都不会影响其他的用户,弊端是无法配置管理其他用户的python环境。 (不排除可能是我自己的试验和理解有误)

    Virtualenv

    写的有点累了,今天先到这里,后续如果有用到或者想起了,再跟新吧,详情可参考github对应的官网。

    https://github.com/pypa/virtualenv