Python中的模块

一个py文件就是一个模块

模块使用举例:

import os

print(os.__file__) # /usr/lib/python3.5/os.py

上面的import os就使用了一个内置模块os,通过os.__file__可以获得本地这个模块的路径

包管理工具pip

类似于Node中的npm,不多赘述,直接来看看使用。

直接sudo pip3 install pygame

安装好了模块之后,运行:

import os
import pygame

print(os.__file__) # /usr/lib/python3.5/os.py
print(pygame.__file__) # /usr/local/lib/python3.5/dist-packages/pygame/__init__.py

实现一个本地模块及模块的引用

先在当前目录下创建一个新的模块testModule.py

# testModule.py
def test1():
    print('----test1----')

对testModule模块进行引用

# import testModule

# testModule.test1() # ----test1----

from testModule import test1

test1()

有上述两种方式。

对于模块的查找,也是优先当前目录,然后才去系统的文件夹下寻找模块

模块中的__name____all__

__name__

先来看__name__的用法:

修改testModule.py:

def test1():
    print('----test1----')


print(__name__) 

当通过python3.5 testModule.py时,输出__main__

我们现在在其他文件中引入这个testModule,然后调用test1():

import testModule

testModule.test1()

此时输出的__name__为testModule

所以:

  • 当文件是被直接执行时,__name__的值为__main__
  • 而当模块是被调用时,__name__为模块名

__all__

__all__是针对from moduleName import *这种模块导入方式的:

当我们写下from moduleName import *,这个模块的所有全局变量,函数或者类,都可以被访问。为了自定义模块的输出,可以使用__all__来规定想输出的函数,变量或者类。

来看例子:
我们有如下模块


class Test(object):
    def sayHi(self):
        print('class Test')


def test1():
    print('---test1---')

num = 100

当在其他模块中引入时:

from testModule import *

t = Test()
t.sayHi()

test1()

print(num)
# 输出
# class Test
# ---test1---
# 100

所有的类,函数,全局变量都可以被访问。

现在我们在testModule.py中设置__all__

__all__ = ['Test','test1']

class Test(object):
    def sayHi(self):
        print('class Test')


def test1():
    print('---test1---')

num = 100

我们在__all__中指定了想要暴露出来的东西,Test这个类和test1这个函数

此时运行结果为:

from testModule import *

t = Test()
t.sayHi() # class Test

test1() # ---test1---

print(num) # NameError: name 'num' is not defined

此时num就访问不到了,这就是__all__的作用。

__init__.py

假设我们现在有sendMsg.py和recvMsg.py两个模块,因为这两个模块在功能上有一定的联系,所以我们可以创建一个新的文件夹,把这两个模块放进去,这个新的文件夹可以当做这2个模块的集合。

但是这样有个问题,需要我们在创建的文件夹中新创建一个__init__.py,否则py2中不允许导入(py3允许,但是也使用不了)

我们现在的文件结构是这样的:

├── Msg
│   ├── recvMsg.py
│   └── sendMsg.py

这个Msg就是我们创建好的集合,现在创建__init__.py

├── Msg
│   ├── __init__.py
│   ├── recvMsg.py
│   └── sendMsg.py

现在这个Msg就变成了一个包,然后我们可以在__init__.py中定义__all__变量来控制想暴露的模块:

# __init__.py
__all__ = ['sendMsg','recvMsg']

我们可以在外部:

from Msg import *

sendMsg.test1() # ----sendMsg----
recvMsg.test1() # ----recvMsg-----

另外,在导入Msg这个包的时候,会执行__init__.py这个文件,所以我们可以在内部引入包中的模块,比如sendMsg和recvMsg。

但是由于Python2和Python3在写法上有差异,在这给出一种通用的写法:

# __init__.py
# -*- coding:utf-8 -*-  

__all__ = ['sendMsg','recvMsg']

# import sendMsg,recvMsg # Py2写法 Py3报错
from . import sendMsg,recvMsg

模块的发布

先来准备一个文件夹,里面放入我们写好的包

.
├── prepare2Publish
│   ├── __init__.py
│   └── sendHello.py
└── setup.py

其中prepare2Publish就是我们想发布的包,我们要在setup.py中设置包的各种信息:

# setup.py

from distutils.core import setup

setup(
    name='DeeJay',
    version='1.0',
    description='a test module',
    author='DeeJay',
    py_modules=['prepare2Publish.sendHello']
)

然后要输入命令:python3 setup.py build来构建(python setup.py build为构建py2的包):

build之后,现在目录结构为:

.
├── build
│   └── lib
│       └── prepare2Publish
│           ├── __init__.py
│           └── sendHello.py
├── prepare2Publish
│   ├── __init__.py
│   └── sendHello.py
└── setup.py

然后输入:python3 setup.py sdist进行压缩

压缩之后,目录结构为:

.
├── build
│   └── lib
│       └── prepare2Publish
│           ├── __init__.py
│           └── sendHello.py
├── dist
│   └── DeeJay-1.0.tar.gz
├── MANIFEST
├── prepare2Publish
│   ├── __init__.py
│   └── sendHello.py
└── setup.py

打成的这个压缩包就是我们最终的模块,可以拿来给别人使用。

解压之后可以通过python3 setup.py install就可以安装到本地的系统包里

另外如果我们想发布到pip官网上,可以使用twine,在~路径下配置好自己的.pypirc, 就可以将自己的压缩包发布到pip官网了

import时模块文件的查询路径 sys.path


import sys

print( sys.path )

# 输出:
[
    '/home/deejay/learn-python', 
    '/usr/lib/python35.zip', 
    '/usr/lib/python3.5', 
    '/usr/lib/python3.5/plat-x86_64-linux-gnu', 
    '/usr/lib/python3.5/lib-dynload', 
    '/home/deejay/.local/lib/python3.5/site-packages', 
    '/usr/local/lib/python3.5/dist-packages', 
    '/usr/lib/python3/dist-packages'
]

sys.path是一个列表,其中每一个元素都是一个路径,第一个元素为当前目录下的路径

当我们导入一个模块的时候,程序会依次从sys.path中去寻找,如果最后没找到就抛出异常

此外我们可以通过给sys.path append()一个自定义的路径,让程序去指定目录寻找模块

例如:

    sys.path.append('/home')

模块的重新导入

重新导入指的是,在当前程序中导入了一个目标模块,然后在程序没有退出的情况下,修改了目标模块的代码。

此时在当前程序中,是不会更新模块的,就算再次import也无法更新.

这个时候,我们可以借助imp模块中的reload()方法来进行不退出程序并且可以更新模块的操作:

from imp import *

reload(targetModule)

模块的循环导入

循环导入即: 在a模块中导入b,同时在b模块中导入a。

# a.py

import b

def test():
    print('----a----')
    b.test()

test()
# b.py

import a

def test():
    print('----b----')
    a.test()

test()

对于这种情况,一个比较好的解决方法是:通过一个主模块来引入所有子模块,子模块中避免相互引入:

比如我们现在新增一个main.py:


# main.py

import a
import b

a.test()
b.test()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 在Python中有一个概念叫做模块(module),这个和C语言中的头文件以及Java中的包很类似,比如在Pyth...
    一只写程序的猿阅读 4,020评论 0 3
  • 1.1模块的介绍 一些功能聚合的xxx.py文件被称为模块,模块分系统自带的,第三方的还有自定义的. 导入模块的方...
    橙子只涩不酸阅读 262评论 0 0
  • 与在控制台输入python程序,执行命令相比。当我们的程序变得越来越长的时候,我们希望可以在文本编辑器(如subl...
    Jason_Yuan阅读 730评论 0 1
  • Python 面向对象Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对...
    顺毛阅读 4,241评论 4 16
  • 今天看了招财猫翁子棋女士的文章《女人,不要嫁在中国》,其中提到了婚姻法的新司法解释,颇为女性朋友们鸣起不平来。那篇...
    老撒阅读 962评论 0 12