社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

[译]python代码入口点

一个普普通通简简单单平平凡凡的神 • 5 年前 • 620 次点击  
原文链接:
amir.rachum.com/blog/2017/0…
(随心所欲翻译.)

这篇文章将会聊聊python代码中的入口点.很多人可能知道,入口点一般会放在setup.py 文件中,经过打包后可以作为命令行使用,不过很少有人会去用它.接下来,我将会介绍如何使用入口点生成python包,之后就可以让别人在代码中或者命令行下使用.

安装过python包的都知道使用pip install <somepackages> , setup.py就是定义了你自己开发的包的相关信息,然后可以打包上传到python的包管理中心供别人下载.而入口点entry_points可以让包作为命令行工具使用.

Snek,Inc.

恭喜你!你刚刚被任命为"snek半导体和软件公司"的CEO,作为CEO,你的第一个工作是让员工开发出snek的原型系统,很快,工程师就做出来了,它是一个python脚本,snek.py:

  ascii_snek = """\
      --..,_                     _,.--.
         `'.'.                .'`__ o  `;__.
            '.'.            .'.'`  '---'`  `
              '.`'--....--'`.'
                `'--....--'`
  """
  ​
  def main():
      print(ascii_snek)
      
  if __name__ == '__main__':
      main()

在公司产品发布的那一天,你演示了这个原型系统,运行很顺利:

  $ python snek.py
      --..,_                     _,.--.
         `'.'.                .'`__ o  `;__.
            '.'.            .'.'`  '---'`  `
              '.`'--....--'`.'
                `'--....--'`

SaaS--Snek as a Service

不幸的是,用户不会使用python,他们只想在电脑的命名行下直接使用Snek的服务,于是工程师们加班加点作出了下一个版本,让snek在安装时自动生成控制台脚本,这样就可以在命令行下运行了.他们是怎么做的?只需要在setup.py 脚本中包含包名,依赖等信息,像下面这样:

下面的代码就是指定了应该从snek脚本的main函数开始执行.
  from setuptools import setup
  ​
  setup(
      name='snek',
      entry_points={
          'console_scripts': [
              'snek = snek:main',
          ],
      }
  )

工程师说,控制台脚本就是特殊的入口点,setuptools 在你的包被别人安装时,读取其中的内容并生成某些脚本文件.现在,让我们从源代码中安装(当然你可以发布为python库,让别人使用pip下载安装):

  $ python setup.py develop
  ​
  running develop
  running egg_info
  writing snek.egg-info\PKG-INFO
  writing dependency_links to snek.egg-info\dependency_links.txt
  writing entry points to snek.egg-info\entry_points.txt
  writing top-level names to snek.egg-info\top_level.txt
  reading manifest file 'snek.egg-info\SOURCES.txt'
  writing manifest file 'snek.egg-info\SOURCES.txt'
  running build_ext
  Creating c:\program files (x86)\py36-32\lib\site-packages\snek.egg-link (link to .)
  snek 0.0.0 is already the active version in easy-install.pth
  Installing snek-script.py script to C:\Program Files (x86)\Py36-32\Scripts
  Installing snek.exe script to C:\Program Files (x86)\Py36-32\Scripts
  Installing snek.exe.manifest script to C:\Program Files (x86)\Py36-32\Scripts
  ​
  Installed c:\users\rachum\notebooks
  Processing dependencies for snek==0.0.0
  Finished processing dependencies for snek==0.0.0

在公司的年度产品会上,你展示了这个amazing的产品:

  $ snek
      --..,_                     _,.--.
         `'.'.                .'`__ o  `;__.
            '.'.            .'.'`  '---'`  `
              '.`'--....--'`.'
                `'--....--'`

Snek for Everyone

没有人不喜欢Snek,公司的IPO超过了60亿美元.有些高级用户希望为他们量身定制高级的版本.工程师又加班加点做了出来:

  """Print an ASCII Snek.
  ​
  Usage:
      snek [--type=TYPE]
      
  """
  import docopt
  ​
  normal_snek = """\
      --..,_                     _,.--.
         `'.'.                .'`__ o  `;__.
            '.'.            .'.'`  '---'`  `
              '.`'--....--'`.'
                `'--....--'`
  """
  ​
  fancy_snek = """\
                            _,..,,,_
                       '``````^~"-,_`"-,_
         .-~c~-.                    `~:. ^-.
     `~~~-.c    ;                      `:.  `-,     _.-~~^^~:.
           `.   ;      _,--~~~~-._       `:.   ~. .~          `.
            .` ;'   .:`           `:       `:.   `    _.:-,.    `.
          .' .:   :'    _.-~^~-.    `.       `..'   .:      `.    '
         :  .' _:'   .-'        `.    :.     .:   .'`.        :    ;
         :  `-'   .:'             `.    `^~~^`   .:.  `.      ;    ;
          `-.__,-~                  ~-.        ,' ':    '.__.`    :'
                                       ~--..--'     ':.         .:'
                                                       ':..___.:'
  """
  ​
  def get_sneks():
      return {
          'normal': normal_snek,
          'fancy': fancy_snek,
      }
  ​
  ​
  def main():
      args = docopt.docopt(__doc__)
      snek_type = args['--type'] or 'normal'
      print(get_sneks()[snek_type])
      
  if __name__ == '__main__':
      main()

他们加了一个豪华版的Snek,这让高级用户特别开心.

  $ snek
      --..,_                     _,.--.
         `'.'.                .'`__ o  `;__.
            '.'.            .'.'`  '---'`  `
              '.`'--....--'`.'
                `'--....--'`
  ​
  $ snek --type fancy
                            _,..,,,_
                       '``````^~"-,_`"-,_
         .-~c~-.                    `~:. ^-.
     `~~~-.c    ;                      `:.  `-,     _.-~~^^~:.
           `.   ;      _,--~~~~-._       `:.   ~. .~          `.
            .` ;'   .:`           `:       `:.   `    _.:-,.    `.
          .' .:   :'    _.-~^~-.    `.       `..'   .:      `.    '
         :  .' _:'   .-'        `.    :.     .:   .'`.        :    ;
         :  `-'   .:'             `.    `^~~^`   .:.  `.      ;    ;
          `-.__,-~                  ~-.        ,' ':    '.__.`    :'
                                       ~--..--'     ':.         .:'
                                                       ':..___.:'

Snek International Community

全球数百万人都在使用snek,人们对snek不同版本的需求越来越高,而且一些snek的专业用户(程序员)要求snek可以定制,他们想开发自己的snek版本.

  """Print an ASCII Snek.
  ​
  Usage:
      snek [--type=TYPE]
      
  """
  import docopt
  import pkg_resources
  ​
  normal_snek = """\
      --..,_                     _,.--.
         `'.'.                .'`__ o  `;__.
            '.'.            .'.'`  '---'`  `
              '.`'--....--'`.'
                `'--....--'`
  """
  ​
  fancy_snek = """\
                            _,..,,,_
                       '``````^~"-,_`"-,_
         .-~c~-.                    `~:. ^-.
     `~~~-.c    ;                      `:.  `-,     _.-~~^^~:.
           `.   ;      _,--~~~~-._       `:.   ~. .~          `.
            .` ;'   .:`           `:       `:.   `    _.:-,.    `.
          .' .:   :'    _.-~^~-.    `.       `..'   .:      `.    '
         :  .' _:'   .-'        `.    :.     .:   .'`.        :    ;
         :  `-'   .:'             `.    `^~~^`   .:.  `.      ;    ;
          `-.__,-~                  ~-.        ,' ':    '.__.`    :'
                                       ~--..--'     ':.         .:'
                                                       ':..___.:'
  """
  ​
  def get_sneks():
      sneks = {
          'normal': normal_snek,
          'fancy': fancy_snek,
      }
      for entry_point in pkg_resources.iter_entry_points('snek_types'):
          sneks[entry_point.name] = entry_point.load()
      return sneks
  ​
  ​
  def main():
      args = docopt.docopt(__doc__)
      snek_type = args['--type'] or 'normal'
      print(get_sneks()[snek_type])
      
  if __name__ == '__main__':
      main()

他们增加了snek的基础架构,当snek运行时,使用被称作snek_types 的入口点注册其他类型的snek,这样就能动态的在控制台输出不同的snek版本.

具体来说,get_sneks 中的pkg_resources.iter_entry_points('snek_types') 遍历所有注册到入口点的snek名,然后加入snek版本中.于是,开发者们加入了一个可爱版本的snek,命名为cute_snek.py

  cute_snek = r"""
                      /^\/^\
                    _|__|  O|
           \/     /~     \_/ \
            \____|__________/  \
                   \_______      \
                           `\     \                 \
                             |     |                  \
                            /      /                    \
                           /     /                       \
                         /      /                         \ \
                        /     /                            \  \
                      /     /             _----_            \   \
                     /     /           _-~      ~-_         |   |
                    (      (        _-~    _--_    ~-_     _/   |
                     \      ~-____-~    _-~    ~-_    ~-_-~    /
                       ~-_           _-~          ~-_       _-~ 
                          ~--______-~                ~-___-~
  """

如何找到这个可爱版本的snek呢?像下面这样定义setup.py

代码中指定了从cute_snek.py脚本寻找cute_snek.
  from setuptools import setup
  ​
  setup(
      name='cute_snek',
      entry_points={
          'snek_types': [
              'cute = cute_snek:cute_snek',
          ],
      }
  )

然后像之前一样打包:

  $ cd cute_snek && python setup.py develop
  running develop
  running egg_info
  writing cute_snek.egg-info\PKG-INFO
  writing dependency_links to cute_snek.egg-info\dependency_links.txt
  writing entry points to cute_snek.egg-info\entry_points.txt
  writing top-level names to cute_snek.egg-info\top_level.txt
  reading manifest file 'cute_snek.egg-info\SOURCES.txt'
  writing manifest file 'cute_snek.egg-info\SOURCES.txt'
  running build_ext
  Creating c:\program files (x86)\py36-32\lib\site-packages\cute-snek.egg-link (link to .)
  cute-snek 0.0.0 is already the active version in easy-install.pth
  ​
  Installed c:\users\rachum\cute_snek
  Processing dependencies for cute-snek==0.0.0
  Finished processing dependencies for cute-snek==0.0.0

现在我们就能在命令行下成功的运行这个可爱版本的snek,这是从 cute_snek中动态加载的:

  $ snek --type cute
                      /^\/^\
                    _|__|  O|
           \/     /~     \_/ \
            \____|__________/  \
                   \_______      \
                           `\     \                 \
                             |     |                  \
                            /      /                    \
                           /     /                       \
                         /      /                         \ \
                        /     /                            \  \
                      /     /             _----_            \   \
                     /     /           _-~      ~-_         |   |
                    (      (        _-~    _--_    ~-_     _/   |
                     \      ~-____-~    _-~    ~-_    ~-_-~    /
                       ~-_           _-~          ~-_       _-~ 
                          ~--______-~                ~-___-~
  ​

既然cute_snek可以动态的加载,那么所有类型的snek应该都可以动态加载,于是工程师们又修改了代码:

所有的snek都从snek_types中加载.
  from setuptools import setup
  ​
  setup(
      name='cute_snek',
      entry_points={
          'snek_types': [
              'cute = cute_snek:cute_snek',
              'normal = snek:normal_snek',
              'fancy = snek:fancy_snek',
          ],
      }
  )
  ​
  # 同时修改之前文件中的get_sneks()函数:
  def get_sneks():
      #sneks = {
      #   'normal': normal_snek,
      #    'fancy': fancy_snek,
      #}
      # 将snek修改为空字典
      snek = {}
      for entry_point in pkg_resources.iter_entry_points('snek_types'):
          sneks[entry_point.name] = entry_point.load()
      return sneks

现在重新打包snek:

  $ python setup.py develop
  running develop
  running egg_info
  writing snek.egg-info\PKG-INFO
  writing dependency_links to snek.egg-info\dependency_links.txt
  writing entry points to snek.egg-info\entry_points.txt
  writing top-level names to snek.egg-info\top_level.txt
  reading manifest file 'snek.egg-info\SOURCES.txt'
  writing manifest file 'snek.egg-info\SOURCES.txt'
  running build_ext
  Creating c:\program files (x86)\py36-32\lib\site-packages\snek.egg-link (link to .)
  snek 0.0.0 is already the active version in easy-install.pth
  Installing snek-script.py script to C:\Program Files (x86)\Py36-32\Scripts
  Installing snek.exe script to C:\Program Files (x86)\Py36-32\Scripts
  Installing snek.exe.manifest script to C:\Program Files (x86)\Py36-32\Scripts
  ​
  Installed c:\users\rachum\notebooks
  Processing dependencies for snek==0.0.0
  Finished processing dependencies for snek==0.0.0

大功告成!!!

  $ snek
      --..,_                     _,.--.
         `'.'.                .'`__ o  `;__.
            '.'.            .'.'`  '---'`  `
              '.`'--....--'`.'
                `'--....--'`
  ​
  $ snek --type fancy
                            _,..,,,_
                       '``````^~"-,_`"-,_
         .-~c~-.                    `~:. ^-.
     `~~~-.c    ;                      `:.  `-,     _.-~~^^~:.
           `.   ;      _,--~~~~-._       `:.   ~. .~          `.
            .` ;'   .:`           `:       `:.   `    _.:-,.    `.
          .' .:   :'    _.-~^~-.    `.       `..'   .:      `.    '
         :  .' _:'   .-'        `.    :.     .:   .'`.        :    ;
         :  `-'   .:'             `.    `^~~^`   .:.  `.      ;    ;
          `-.__,-~                  ~-.        ,' ':    '.__.`    :'
                                       ~--..--'     ':.         .:'
                                                       ':..___.:'
  ​
  $ snek --type cute
                      /^\/^\
                    _|__|  O|
           \/     /~     \_/ \
            \____|__________/  \
                   \_______      \
                           `\     \                 \
                             |     |                  \
                            /      /                    \
                           /     /                       \
                         /      /                         \ \
                        /     /                            \  \
                      /     /             _----_            \   \
                     /     /           _-~      ~-_         |   |
                    (      (        _-~    _--_    ~-_     _/   |
                     \      ~-____-~    _-~    ~-_    ~-_-~    /
                       ~-_           _-~          ~-_       _-~ 
                          ~--______-~                ~-___-~

到此为止,你应该大概知道了如何使用python中的入口点了吧.


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/Q6TE4utyLS
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/13277
 
620 次点击