在网上找到一篇介绍Python egg的文档,自觉egg是Python编程中关键的一环,遂决定翻译一下这篇文档,以加深自己的理解。
Python eggs - 简介
Python eggs曾经是未来的浪潮。但对于Zope和Plone开发者来说,这个浪潮已经演变成海啸了。它们现在无处不在。然而,人们对于Python egg是什么、怎么用仍有很多疑惑。要理解它们,必须先理解Python 组织代码文件的方式。
一、模块
在Python中,模块是实现代码重用的基本单位:(一个模块可以包含一个或多个代码块),代码块的代码可以被另一些代码导入使用(这就是Python 的代码可重用性)。在Python中,模块常常以单独的后缀为.py的文件出现,这样的文件也被称为脚本。如:
hello.py
假设这个hello.py里面包含一个函数:
def helloworld():
print 'Hello World'
这样的话,在别的代码之中,如果我们想用到这个函数,可以像这样导入:
from hello import helloworld
二、包
包就是一个包含其他模块的模块,这些模块通常位于一个目录下,并以一个__init__.py文件将这个目录与文件系统中其他目录区分开来。
脚本之上(这个说法可能跟Python组织代码文件的方式有关)就是模块,这个模块也就是一个带有__init__.py文件的库:
hello/
__init__.py
你可以把上面的helloworld函数放进这个__init__.py脚本中,然后像之前那样去导入它:
from hello import helloworld
你也可以保留这个函数在之前的hello.py文件中,把这个文件放入hello目录中:
hello/
__init__.py
hello.py
这样的话,如果你要使用helloworld函数,必须这样导入:
from hello.hello import helloworld
除非你把这个函数导入到模块命名空间,在脚本__init__.py中添加:
from hello import helloworld
然后,你可以像之前那样导入使用helloworld函数了:
from hello import helloworld
这样做可以确保你能重新组织你的代码,并且使你的代码保持向后兼容。你可以在模块里包含模块。一个Python库实际上就是一个模块,或者说是诸多模块组织在一起的一个结构。这样的结构,被叫做包。
三、Distutils
到目前为止,这篇文章都是关于编写和组织Python代码的。下一步是关于分发上述代码的。首先,我们要了解Distutils模块。Distutils模块的目的是为了统一Python模块和包的安装方式。基本上,你只需要用命令行cd到某个模块/包的安装目录,运行如下命令:
python setup.py install
然后这个模块/包就会自动安装在相应的python环境中。
Distutils 在你的模块之外定义了一个“目录/文件”结构,这个结构与你的模块本身没有任何关系,但却是被用来分发这个模块的。
如果你想对上面的hello模块/包进行分发,你必须把它放进某个含有setup.py文件的文件目录之中,像这样:
somedir/ # 某个文件目录
setup.py # 目录下必须包含这个
hello/ # 要分发的模块/包
__init__.py
hello.py
这个setup.py中可以包含以下代码,这些代码运行setup函数:
from distutils.core import setup
setup( name = 'hello',
version = '1.0',
packages = ['hello'],
)
然后你可以输入如下命令去运行这些代码:
python setup.py sdist
运行结果是创建了如下的新的目录结构:
somedir/
setup.py
hello/
__init__.py
hello.py
dist/ # 新增的
hello-1.0.tar.gz # 新增的
这个hello-1.0.tar.gz就是用来分发包的。如果将其解包,会发现它的结构是这样的:
hello-1.0/ # 仅仅多了“-1.0”这个版本号,不是新的
PKG-INFO # 新增的
setup.py
hello/
__init__.py
hello.py
可以看到,hello包就在这个结构中,这个包只是前面你自己创建的hello包的复制品,两者完全一样。setup.py文件也在这个结构中,它是你创建hello包时所写的setup.py的复制品。Distutils模块的巧妙之处在于,它能用同样的脚本去创建包的分发以及下载安装该包。PKG-INFO 是一个新文件,它只包含这个包的一些元数据。这些数据能在setup.py中设置。
四、Setuptools
Setuptools是建立在Distils顶层的。它让在pypi上保存模块成为可能。它通过eggs进行分发。
五、Eggs
egg的创建跟distutil包的创建十分相似,你只需要将后者的setup.py的脚本改动一行:
from setuptools import setup # 就是这行
setup( name = 'hello',
version = '1.0',
packages = ['hello']
)
然后你可以通过以下命令去运行上面的脚本:
python setup.py bdist_egg
然后你会在dist目录下得到一个新文件:
dist/
hello-1.0-py2.4.egg
这就是那个你能放到网站上,甚至更好,放到pypi上面的egg了。你可以注册一个pypi账号,然后通过如下命令,把你的egg添加到pypi上面去:
setup.py bdist_egg upload
六、Easy_install
当你上传完你的egg,全世界都能够通过easy_install 安装使用它:
easy_install hello
运行这个命令后,easy_install 会在pypi上找到、下载、如果需要的话会编译这个egg,并把它添加到你的sys.path中去,以便Python能够发现它。
七、Buildout
Buildout 是一个基于配置文件的系统,通过它我们可以为大型系统创建复杂但可重用的设置。唷!听起来很复杂。好吧,Buildout的确可以这样复杂。但有意思的是,从eggs的角度看,你可以在Buildout中设定哪些eggs将要安装在你的系统中。在你的buildout.cfg文件中,你可以有这样一行:
eggs =
hello
然后,Buildout会自动下载并安装hello包在你的系统中。
Buildouts本身能够以eggs的形式进行分发,并且你可以扩展一个Buildout,在其中添加新的包。这就是你安装一个Plone buildout然后往里面添加你自己的包的方式。这基本上创建了你的定制版的Plone分发。
________________________________________________________________________
渣翻译求板砖求指正。
_________________________________________________________________________
附原文(稍微重排了一下):
Python eggs - a Simple Introduction
Python eggs used to be the wave of the future. But for Zope and Plone developers this has evolved into a true tsunami. They are everywhere now. Yet there is a lot of confusion of what they are and how to use them. To understand them, you need to understand Python's way of organizing code files.
Module
The basic unit of code reusability in Python: a block of code imported by some other code. It is most often a module written in Python and contained in a single .py file. Also called a script.
hello.py
Let us say that this hello.py contains a function:
def helloworld():
print 'Hello World'
Then it is possible to import that function like this:
from hello import helloworld
Package
A module that contains other modules; typically contained in a directory in the file system and distinguished from other directories by the presence of a file __init__.py.
A step up from a script is a module, which is a library with an __init__.py file in it.
hello/
__init__.py
You can then put the helloworld function into the __init__.py script, and import it like you did before:
from hello import helloworld
You could also keep it in the hello.py file from before.
hello/
__init__.py
hello.py
But then you must import it like this:
from hello.hello import helloworld
Unless you import it into the module namespace. You do this in the __init__.py script:
from hello import helloworld
Then you will once more be able to write:
from hello import helloworld
This ensures the you can reorganize your code and still remain backwards compatibility.
You can have modules inside modules. A python library is just a module, or a structure of modules. A structure of modules is called a package.
Distutils
So far it has all been about writing and organizing Python code. But the next step is distribution of said code. First step in this direction is distutils.
Distutils was written to have a single unified way to install Python modules and packages. Basically you just cd to the directory of the module and write:
python setup.py install
Then the module will automagically install itself in the python it was evoked with.
Distutils defines a directory/file structure outside your module, that has nothing to do with the module per se, but is used distribute the module.
If you want to make a distribution of the hello module you must put it inside a directory that also contains a setup.py file.
somedir/
setup.py
hello/
__init__.py
hello.py
The setup.py could contains this code, that runs the setup function:
from distutils.core import setup
setup(name='hello',
version='1.0',
packages=['hello',],
)
You then run the code like this:
python setup.py sdist
And it will create a new directory structure like this:
somedir/
setup.py
hello/
__init__.py
hello.py
dist/
hello-1.0.tar.gz
The hello-1.0.tar.gz then contains the package distribution. It has this structure when unpacked:
hello-1.0/
PKG-INFO
setup.py
hello/
__init__.py
hello.py
The hello package is inside it. It is just a copy of your own package with no changes.
setup.py is there too. It is also just a copy of the one you wrote to create the package with. The clever thing about distutils is that it can use the same script to create the distribution as it use to install the package.
PKG-INFO is a new file and it just contains some metadata for the package.
Those can be set in the setup.py.
Setuptools
Setuptools is built on top of distutils. It makes it possible to save modules in pypi, or somewhere else. It uses eggs for distribution.
Eggs
An egg is created very much like a distutil package. You just have to change a line in your setup.py
from setuptools import setup # this is new
setup(name='hello',
version='1.0',
packages=['hello',],
)
Then you call it with:
python setup.py bdist_egg
And you get a new file in your dist directory:
dist/
hello-1.0-py2.4.egg
This is the egg that you can put on your website, or even better, publish to pypi. you can get an account on pypi, and then you will be able to add your eggs via the command line like:
setup.py bdist_egg upload
Easy_install
When you have uploaded your egg, all the world is able to use it by installing it with easy_install:
easy_install hello
Easy install will then find the egg on pypi, download it, compile if necessary and add it to your sys.path so that Python will find it.
Buildout
Buildout is a configuration based system for making complicated but repeatable setups for large systems.
Phew. That sounds complicated. Well buildout can be. But what is interesting from an eggs based point of view is that you configure what eggs are to be installed in your system.
Inside your buildout.cfg you can have a line like:
eggs =
hello
Then buildout will automatically download and install the hello package in your system.
Buildouts can themself be distributed as eggs, and you can extend a buildout to add new packages. This is how you can install a Plone buildout and then add your own packages to it. Basically creating your own custom Plone distributions.