python模块&类的导入.md

定义模块、包

在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。

为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,

在Python中,一个.py文件就称之为一个模块(Module)。

使用模块有什么好处?

  • 最大的好处是大大提高了代码的可维护性。
  • 编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。
  • 使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中

但是如果不同的人编写的模块名相同怎么办?

为了避免模块名冲突,Python又引入了按目录来组织模块的方法,称为包(Package)。其他的语言可能就叫“命名空间”

比如一个abc.py的文件就是一个名字叫abc的模块,如果abc与其他模块冲突了,可以选择一个顶层的包mycompany来避免冲突。

那么引用的时候需要注意,是mycompany.abc而不是abc

另外需要注意的是在每个包目录下需要有一个__init__.py,否则会把目录当做普通的目录。
init.py可以是空文件,也可以有Python代码,因为__init__.py本身就是一个模块,而它的模块名就是mycompany。

自己创建模块时要注意命名,不能和Python自带的模块名称冲突

使用模块

使用内置模块

比如导入sys模块:

import sys

导入sys模块后,我们就有了变量sys指向该模块,利用sys这个变量,就可以访问sys模块的所有功能。

sys模块有一个argv变量,用list存储了命令行的所有参数。argv至少有一个元素,因为第一个参数永远是该.py文件的名称

使用自定义模块

导入自定义模块可以分为静态导入和动态导入。
静态导入指的是在文件的开头的时候使用import语句进行一次导入,动态导入是在需要使用的时候再动态的导入,这样就可以在runtime的时候导入模块,而不是在文件的开头一次性导入,更为灵活。

静态导入

静态导入主要通过import或者from语句。

多次import同一个模块,只有第一次有效。

这两种语句的区别:

比如下图中,想导入libs.Model.testModelClass模块里面的类testModel
首先需要在Model文件夹下建立__init__.py文件。

  • import libs.Model.testModelClass: 这些子项必须是包,最后的子项是包或模块。但不能为函数、类或变量,所以实际上没有得到正确的结果。如果想要实例化类,必须将包名写全,也即testModelInstance = libs.Model.testModelClass.testModel()
  • from libsModel.testModelClass import testModel:这种方式item可以是包中的一个子模块或子包,也可以是包中定义的其他命名,像函数、类、变量。所以可以正确引入testModel,可以使用testModelInstance = testModel()进行实例化。

使用from导入变量,如果和作用域中现有的变量同名,本地变量就会被悄悄地覆盖掉;使用import则没这个问题。

动态导入

静态导入类似常量,只能导入名字已经确定的模块。但是有这样一种情况,如果希望定义一个函数,传入导入的模块的包和模块的名称,然后进行导入,使用静态导入是不能实现的。
动态导入一般可以使用__import__()函数,等价于import语句。

但是如果要导入模块中的变量或者类需要结合反射。

先介绍一下getattr()这个python内置函数。

getattr(object, name[,default]):获取对象object的属性或者方法

  • 如果存在则打印出来
  • 如果不存在,打印出默认值,默认值可选。

如果是返回的对象的方法,返回的是方法的内存地址,所以只要在后面添加一对括号,就可以运行这个方法。
比如:

 class test():
 ...     name="xiaohua"
 ...     def run(self):
 ...             return "HelloWord"

下面演示一下反射:

>>> t=test()
>>> getattr(t, "name") #获取name属性,存在就打印出来。
'xiaohua'
>>> getattr(t, "run")  #获取run方法,存在就打印出方法的内存地址。

那么如果要动态的导入上一节里面的那个例子里面的libs.Model.testModel模块中的testModelClass应该怎么办呢?

    libs = __import__('libs.Model.testModelClass');#动态的导入
    model = getattr(libs , "Model");#通过反射一步一步获得模块testModelClass
    testModelClass= getattr(model , 'testModelClass');
    testModel = getattr( testModelClass, "testModel");#通过反射获得类testModel
    obj = testModel();#实例化类
    get = getattr(testModel , "get");#调用testModel类中的get()方法。
    get(obj);

有人会说这有什么用?

比如libs.Model下面可能不是testModelClass,可以是authModelClass的模块,里面的类也相应改变为authModel。那么有没有办法定义一个M(name , method),实现的功能是导入libs.Model.authModelClass下的authModel类并进行实例化。同时调用method方法。

def M(name, method):
    libs = __import__('libs.Model.'+name+'ModelClass');#动态的导入
    model = getattr(libs , "Model");#通过反射一步一步获得模块testModelClass
    testModelClass= getattr(model , name+'ModelClass');
    testModel = getattr( testModelClass, name+"Model");#通过反射获得类testModel
    obj = testModel();#实例化类
    mtd = getattr(testModel , method);#调用testModel类中的get()方法。
    mtd(obj);
    

如果要调用,可以直接使用M("auth","get");,相当于调用引入了模块和类,并进行实例化,然后调用authModel.get()方法。

安装第三方模块

上面主要讲的是自己写模块,但是实际上python作为一个”胶水语言“,很多功能已经被别人实现了,我们没有必要自己重复的实现一部分,一定要有”拿来主义“

安装第三方模块,是通过包管理工具pip完成的。

注意在安装python的时候,确保安装时勾选了pip和Add python.exe to Path。

在命令提示符窗口下尝试运行pip,如果Windows提示未找到命令,可以重新运行安装程序添加pip。

注意:Mac或Linux上有可能并存Python 3.x和Python 2.x,因此对应的pip命令是pip3。

比如安装excel处理工具xlrd。

pip install xlrd

但是pip源在国外(你懂的),所以下载会比较慢,可以使用国内的镜像,比如豆瓣。

pip install -i http://pypi.douban.com/simple/  xlrd --trusted-host pypi.douban.com

模块搜索路径

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

默认情况下,Python解释器会搜索当前目录、所有已安装的内置模块和第三方模块,搜索路径存放在sys模块的path变量中,如果我们要添加自己的搜索目录,有两种方法

  • 直接修改sys.path,添加要搜索的目录:
>>> import sys
>>> sys.path.append('/Users/michael/my_py_scripts')
  • 设置环境变量PYTHONPATH,该环境变量的内容会被自动添加到模块搜索路径中。设置方式与设置Path环境变量类似。注意只需要添加你自己的搜索路径,Python自己本身的搜索路径不受影响。
posted @ 2017-10-29 16:24  dy2903  阅读(4201)  评论(0编辑  收藏  举报