解释Python入口点?

277 投票
3 回答
175019 浏览
提问于 2025-04-15 11:12

我看过关于Pylons中的egg入口点和Peak页面的文档,但我还是不太明白。有人能给我解释一下吗?

3 个回答

22

从抽象的角度来看,入口点是用来创建一个系统范围内的注册表,里面记录了实现特定接口的Python可调用对象。pkg_resources里有一些API,可以查看某个包提供了哪些入口点,也可以用来确定哪些包提供了某个特定的入口点。

入口点的好处在于,它允许一个包使用另一个包中的插件。比如,Ian Bicking的Paste项目就大量使用了入口点。在这种情况下,你可以编写一个包,通过入口点paste.app_factory来宣传它的WSGI应用工厂。

入口点的另一个用途是列出系统中所有提供某些插件功能的包。TurboGears这个网页框架使用python.templating.engines入口点来查找已安装和可用的模板库。

226

入口点(EntryPoints) 是一种持久的、基于文件系统的对象名称注册和基于名称的直接对象导入机制,这个机制是通过setuptools这个包来实现的。

它们将Python对象的名称与自由格式的标识符关联起来。这样,任何其他使用相同Python安装并知道这个标识符的代码,都可以访问与该名称关联的对象,无论这个对象在哪里定义。关联的名称可以是Python模块中存在的任何名称;比如类名、函数名或变量名。入口点机制并不关心这个名称指的是什么,只要它是可以导入的。

举个例子,我们可以用一个函数的名称,以及一个假想的Python模块,完全限定名为'myns.mypkg.mymodule':

def the_function():
   "function whose name is 'the_function', in 'mymodule' module"
   print "hello from the_function"

入口点是通过在setup.py中声明入口点来注册的。要将the_function注册为名为'my_ep_func'的入口点,可以这样做:

    entry_points = {
        'my_ep_group_id': [
            'my_ep_func = myns.mypkg.mymodule:the_function'
        ]
    },

如例子所示,入口点是分组的;有相应的API可以查找属于某个组的所有入口点(下面有示例)。

在安装一个包时(也就是运行'python setup.py install'),setuptools会解析上述声明。然后,它会将解析的信息写入一个特殊文件中。之后,可以使用pkg_resources API(这是setuptools的一部分)来查找入口点并访问与之关联的对象:

import pkg_resources

named_objects = {}
for ep in pkg_resources.iter_entry_points(group='my_ep_group_id'):
   named_objects.update({ep.name: ep.load()})

在这里,setuptools读取了写入特殊文件的入口点信息。它找到了入口点,导入了模块(myns.mypkg.mymodule),并在调用pkg_resources.load()时获取了在那定义的the_function。

调用the_function就变得简单了:

>>> named_objects['my_ep_func']()
hello from the_function

因此,虽然一开始可能有点难以理解,但入口点机制实际上是相当简单易用的。它为可插拔的Python软件开发提供了一个有用的工具。

282

“入口点”通常指的是一个函数(或者其他可以调用的对象),开发者或者使用你这个Python包的人可能会想用到它。不过,也可以提供一个不可调用的对象作为入口点(正如评论中提到的那样!)。

最常见的入口点类型是 console_scripts,它指向一个你希望作为命令行工具提供的函数,任何安装你包的人都可以使用。这个内容会放在你的 setup.py 脚本中,像这样:

entry_points={
    'console_scripts': [
        'cursive = cursive.tools.cmd:cursive_command',
    ],
},

我刚刚发布了一个叫 cursive.tools 的包,我希望它能提供一个“cursive”命令,用户可以在命令行中运行,比如:

$ cursive --help
usage: cursive ...

实现这个功能的方法是定义一个函数,比如在文件 cursive/tools/cmd.py 中创建一个 cursive_command 函数,内容可能是:

def cursive_command():
    args = sys.argv[1:]
    if len(args) < 1:
        print "usage: ..."

接下来,它应该假设是从命令行调用的,解析用户提供的参数,然后……执行这个命令应该做的事情。

安装 docutils 包可以看到一个很好的入口点使用示例:它会安装大约六个有用的命令,用于将Python文档转换成其他格式。

撰写回答