python setup_Python使用setup.py进行简单模块打包

如果想编写一个python模块,分发给别人使用,可以使用setup.py实现模块化。

首先在当目录下新建一个setup.py文件对模块进行描述:from distutils.core import setup

setup(name='shuiguangutils',

version="1.0",

description="shuiguang 's utils",

author="shuiguang",

author_email="",

py_modules=["utils.StringUtils"],

)

上面我使用包名.模块名定义了一个模块,当然可以定义多个包,在包下可以定义多个模块,目录结构如下:|—— setup.py

|—— suba

||——aa.py

||——bb.py

||__ __init__.py

|

|__ subb

|—— cc.py

|—— dd.py

|__ __init__.py

假设我把StringUtils.py放到aa.py的位置,那么还需要在suba包下的__init__.py下引入StringUtils,__init__.py内容如下:from . import StringUtils

比如我将常用的字符串函数放到一个StringUtils.py类中:# -*- coding: utf-8 -*-

import sys

if sys.version_info[0] == 2:

from urlparse import urlparse

else:

from urllib.parse import urlparse

import re

class StringUtils():

@classmethod

def isEmpty(cls, haystack):

if haystack is None:

return True

elif len(haystack) == 0:

return True

else:

return False

接下来使用命令行将刚才写的模块进行编译打包:python setup.py build

running build

running build_py

creating build

creating build/lib

creating build/lib/utils

copying utils/__init__.py -> build/lib/utils

copying utils/StringUtils.py -> build/lib/utils

执行之后会在同级目录下生成一个dist目录,使用tree命令查看层级发现:.

├── MANIFEST

├── __init__.py

├── build

│   └── lib

│       └── utils

│           ├── StringUtils.py

│           └── __init__.py

├── setup.py

└── utils

├── StringUtils.py

└── __init__.py

上面的命令只是将源码拷贝到build目录下,还需执行另一条命令对build目录进行打包:python setup.py sdistpython setup.py sdist

running sdist

running check

warning: check: missing required meta-data: url

warning: sdist: manifest template 'MANIFEST.in' does not exist (using default file list)

warning: sdist: standard file not found: should have one of README, README.txt

writing manifest file 'MANIFEST'

creating shuiguangutils-1.0

creating shuiguangutils-1.0/utils

making hard links in shuiguangutils-1.0...

hard linking setup.py -> shuiguangutils-1.0

hard linking utils/StringUtils.py -> shuiguangutils-1.0/utils

hard linking utils/__init__.py -> shuiguangutils-1.0/utils

creating dist

Creating tar archive

removing 'shuiguangutils-1.0' (and everything under it)

再次执行tree命令:.

├── MANIFEST

├── __init__.py

├── build

│   └── lib

│       └── utils

│           ├── StringUtils.py

│           └── __init__.py

├── dist

│   └── shuiguangutils-1.0.tar.gz

├── setup.py

└── utils

├── StringUtils.py

└── __init__.py

发现多了一个dist目录,就是刚才打好的包,把这个文件传给别人安装即可。

安装模块也很简单,只需要将此tar.gz的包解压后,使用命令安装即可:python setup.py install

running install

running build

running build_py

creating build

creating build\lib

creating build\lib\utils

copying utils\__init__.py -> build\lib\utils

copying utils\StringUtils.py -> build\lib\utils

running install_lib

creating C:\Python27\Lib\site-packages\utils

copying build\lib\utils\StringUtils.py -> C:\Python27\Lib\site-packages\utils

copying build\lib\utils\__init__.py -> C:\Python27\Lib\site-packages\utils

byte-compiling C:\Python27\Lib\site-packages\utils\StringUtils.py to StringUtils.pyc

byte-compiling C:\Python27\Lib\site-packages\utils\__init__.py to __init__.pyc

running install_egg_info

Writing C:\Python27\Lib\site-packages\shuiguangutils-1.0-py2.7.egg-info

这样就将你的模块安装到别人的全局环境中去了。

我们写一个简单的测试,看看有没有安装成功:from utils.StringUtils import *

print StringUtils.isEmpty("a")

print StringUtils.isEmpty("")

在命令行中同样也可以使用以上方式进行导入StringUtils类下的所有方法:>>> from utils.StringUtils import *

>>> StringUtils.isEmpty("a")

False

>>> StringUtils.isEmpty("")

True

在函数式编程中,如果我们将函数直接写在文件中,而不是封装到某一个类里面,比如:在StringUtils中添加一个全局函数:def strReplaceOnce(haystack, left='', right=''):

return haystack.replace(left, right, 1)

类似这样,导入方式和上面的方式一样:from utils.StringUtils import *

print strReplaceOnce("aba", "b", "c")

事实上,函数式编程中我们不推荐使用import *导入所有的方法,可以在StringUtils.py里定义一个__all__变量:__all__ = ["StringUtils", "strReplaceOnce"]

使用__all__变量可以控制要暴露出去的方法,没有暴露的函数是不能被访问到的,即使是之前定义的那个StringUtils类(python允许一个文件里允许写多个类和全局函数,文件名可以任意),一旦你定义了__all__全局变量,你就必须考虑到哪些东西是需要暴露给import *。

问题:使用模块打包安装解决了软件的分发问题,但是作为项目的依赖模块,每次都需要修改模块代码之后,打包安装才能更新到最新代码吗?

目前,我使用的方式是动态导入方式。

在我的工程中,模块(多个)与我的业务代码在同一个工程下,目录结构大概如下:├── middlewares.py

├── pipelines.py

├── pos.py

├── settings.py

├── shuiguang

│   ├── MANIFEST

│   ├── __init__.py

│   ├── build

│   │   └── lib

│   │       └── utils

│   │           ├── StringUtils.py

│   │           └── __init__.py

│   ├── dist

│   │   ├── shuiguangutils-1.0

│   │   │   ├── PKG-INFO

│   │   │   ├── build

│   │   │   │   └── lib

│   │   │   │       └── utils

│   │   │   │           ├── StringUtils.py

│   │   │   │           └── __init__.py

│   │   │   ├── setup.py

│   │   │   └── utils

│   │   │       ├── StringUtils.py

│   │   │       └── __init__.py

│   │   └── shuiguangutils-1.0.tar.gz

│   ├── setup.py

│   └── utils

│       ├── StringUtils.py

│       └── __init__.py

平时使用相对路径来定位依赖:pipelines.py

# 获取当前执行脚本的位置

pwd = sys.path[0]

# 加载我的扩展工具包

shuiguang = os.path.join(os.path.abspath(pwd), "shuiguang")

os.sys.path.append(shuiguang + os.path.sep + "utils")

StringUtils = __import__("StringUtils")

from StringUtils import *

print StringUtils.isEmpty("")

也就是说,我在middlewares.py和pipelines.py中引用我的模块时是这样的:

关键是需要在python中指定Working Directory(工作空间)

工作空间是当前目录很好将我的所有模块append到环境中,如果是同级子目录spiders下的脚本,导入方式是一样的:spiders/crx.py

# 获取workspace位置

pwd = os.path.abspath('.')

# 加载我的扩展工具包

shuiguang = os.path.join(os.path.abspath(pwd), "shuiguang")

shuiguang = os.path.join(os.path.abspath(pwd), "shuiguang")

os.sys.path.append(shuiguang + os.path.sep + "utils")

StringUtils = __import__("StringUtils")

from StringUtils import *

print StringUtils.isEmpty("")

动态导入在IDE编辑器上还是会有提示说找不到,不太友好,但是可以免除维护两套代码的烦恼。

转载随意~请带上教程地址吧^^

你可能感兴趣的:(python,setup)