V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
codists
V2EX  ›  Python

翻译:《实用的 Python 编程》03_05_Main_module

  •  
  •   codists ·
    codists · 2021-03-05 19:21:23 +08:00 · 1850 次点击
    这是一个创建于 1362 天前的主题,其中的信息可能已经有所发展或是发生改变。

    3.5 主模块

    本节介绍主程序(主模块)的概念

    主函数

    在许多编程语言中,存在一个主函数或者主方法的概念。

    // c / c++
    int main(int argc, char *argv[]) {
        ...
    }
    
    // java
    class myprog {
        public static void main(String args[]) {
            ...
        }
    }
    

    这是启动应用程序时执行的第一个函数。

    Python 主模块

    Python 没有主函数(main function )或主方法( main method )。相反,Python 有一个主模块(main module )。主模块是第一个运行的源文件。

    bash % python3 prog.py
    ...
    

    在应用程序启动时,提供给解释器的任何文件都将成为主模块。名字并不重要。

    __main__ 检查

    对于作为主脚本运行的模块,使用此约定(译注:__main__ 检查)是标准做法。

    # prog.py
    ...
    if __name__ == '__main__':
        # Running as the main program ...
        statements
        ...
    

    if 里面的语句称为主程序( main program )。

    主程序与库导入

    任何 Python 文件都可以作为主程序运行,或者作为一个库(译注:library,在 Python 中 library 既可以指模块 module,也可以指包 package ),导入后运行。

    bash % python3 prog.py # Running as main
    
    import prog   # Running as library import
    

    在这两种情况下,__name__ 都是模块的名称(译注:prog )。然而,如果作为主程序运行,__name__ 只能被设置为 __main__

    通常,我们不希望主程序中的语句在库导入的时候执行。所以,通常在代码中包含一个 if- 检查,判断当前文件是否是主程序(译注:如果当前程序不是主程序,则 if __name__ == '__main__': 里面的语句不执行)。

    if __name__ == '__main__':
        # Does not execute if loaded with import ...
    

    程序模板

    这里有一个用于编写 Python 程序的通用模板:

    # prog.py
    # Import statements (libraries)
    import modules
    
    # Functions
    def spam():
        ...
    
    def blah():
        ...
    
    # Main function
    def main():
        ...
    
    if __name__ == '__main__':
        main()
    

    命令行工具

    Python 通常在命令行工具中使用:

    bash % python3 report.py portfolio.csv prices.csv
    

    这意味着脚本在 shell 或者 终端( terminal )执行。通常用于自动化,后台任务等。

    命令行参数

    命令行参数是一个文本字符串列表。

    bash % python3 report.py portfolio.csv prices.csv
    

    该文本字符串列表可以在 sys.argv 中找到。

    # In the previous bash command
    sys.argv # ['report.py, 'portfolio.csv', 'prices.csv']
    

    这里有一个处理参数的简单示例:

    import sys
    
    if len(sys.argv) != 3:
        raise SystemExit(f'Usage: {sys.argv[0]} ' 'portfile pricefile')
    portfile = sys.argv[1]
    pricefile = sys.argv[2]
    ...
    

    标准 I/O

    标准输入 /输出(或者 stdio )是和普通文件使用相同工作方式的文件。

    sys.stdout
    sys.stderr
    sys.stdin
    

    默认情况下,打印定向到 sys.stdout 文件。输入是从 sys.stdin 文件读取。回溯和错误定向到 sys.stderr 文件。

    请注意,标准输入 /输出(stdio)可以连接到终端( terminals ),文件( files ),管道( pipes )等。

    bash % python3 prog.py > results.txt
    # or
    bash % cmd1 | python3 prog.py | cmd2
    

    环境变量

    环境变量在 shell 中设置。

    bash % setenv NAME dave
    bash % setenv RSH ssh
    bash % python3 prog.py
    

    os.environ 是包含这些值的字典。

    import os
    
    name = os.environ['NAME'] # 'dave'
    

    更改会反映在程序随后启动的任何子进程中。

    程序退出

    通过异常处理程序退出。

    raise SystemExit
    raise SystemExit(exitcode)
    raise SystemExit('Informative message')
    

    其它方式。

    import sys
    sys.exit(exitcode)
    

    非零( non-zero )退出码表示错误。

    #!

    在 Unix 系统中,#! 行指定某个路径下的 Python 解释器来执行该脚本(译注:#! 称为 Shebang 或者 hashbang,因为 # 号通常称为 hash 或者 sharp,而 ! 号则常常称为 bang )。将以下内容添加到脚本文件的第一行。

    #!/usr/bin/env python3
    # prog.py
    ...
    

    (译注:#!/usr/bin/env python3 的意思——到 Unix 系统 env 所包含的全部环境变量中寻找 Python3 解释器,并使用 Python3 解释器执行该脚本)

    执行脚本需要脚本具有可执行权限。

    bash % chmod +x prog.py
    # Then you can execute
    bash % prog.py
    ... output ...
    

    注意:Windows 系统上的 Python 启动器也会寻找 #! 行以指示语言版本。

    脚本模板

    最后,这里有一个通用代码模板,用于将 Python 程序作为命令行脚本运行:

    #!/usr/bin/env python3
    # prog.py
    
    # Import statements (libraries)
    import modules
    
    # Functions
    def spam():
        ...
    
    def blah():
        ...
    
    # Main function
    def main(argv):
        # Parse command line args, environment, etc.
        ...
    
    if __name__ == '__main__':
        import sys
        main(sys.argv)
    

    练习

    练习 3.15:main() 函数

    report.py 文件中添加一个 main() 函数,该函数接受命令行选项列表,并生成与以前相同的输出。修改后,应该能够像下面这样交互地运行它:

    >>> import report
    >>> report.main(['report.py', 'Data/portfolio.csv', 'Data/prices.csv'])
          Name     Shares      Price     Change
    ---------- ---------- ---------- ----------
            AA        100       9.22     -22.98
           IBM         50     106.28      15.18
           CAT        150      35.46     -47.98
          MSFT        200      20.89     -30.34
            GE         95      13.48     -26.89
          MSFT         50      20.89     -44.21
           IBM        100     106.28      35.84
    >>>
    

    请修改 pcost.py 文件,添加一个类似的 main() 函数。

    >>> import pcost
    >>> pcost.main(['pcost.py', 'Data/portfolio.csv'])
    Total cost: 44671.15
    >>>
    

    练习 3.16:编写脚本

    请修改 report.pypcost.py 程序,以便它们在命令行上可以作为脚本执行:

    bash $ python3 report.py Data/portfolio.csv Data/prices.csv
          Name     Shares      Price     Change
    ---------- ---------- ---------- ----------
            AA        100       9.22     -22.98
           IBM         50     106.28      15.18
           CAT        150      35.46     -47.98
          MSFT        200      20.89     -30.34
            GE         95      13.48     -26.89
          MSFT         50      20.89     -44.21
           IBM        100     106.28      35.84
    
    bash $ python3 pcost.py Data/portfolio.csv
    Total cost: 44671.15
    

    注:完整翻译见 https://github.com/codists/practical-python-zh

    8 条回复    2021-03-06 23:25:29 +08:00
    lisniuse
        1
    lisniuse  
       2021-03-05 20:55:31 +08:00
    可以来这儿发帖。https://www.kuxai.com/f/python
    hsfzxjy
        2
    hsfzxjy  
       2021-03-05 21:20:10 +08:00
    改进了一下这一节,交了个 PR
    codists
        3
    codists  
    OP
       2021-03-05 22:21:45 +08:00
    @hsfzxjy
    感谢大佬,这两天我登陆 github 卡死了,过两天网络好点我把它们 merge 了。
    codists
        4
    codists  
    OP
       2021-03-05 22:22:57 +08:00
    @lisniuse
    好嘞,与各位大佬互相交流学习。
    css3
        5
    css3  
       2021-03-05 23:21:35 +08:00 via iPhone
    @codists github 有吗?发下链接我去 stars
    Rrobinvip
        6
    Rrobinvip  
       2021-03-05 23:40:30 +08:00
    好!支持
    codists
        7
    codists  
    OP
       2021-03-06 23:25:03 +08:00
    @css3
    兄 dei,重点是要看进去,学进去啊。单纯的 star 没有意义哈。
    codists
        8
    codists  
    OP
       2021-03-06 23:25:29 +08:00
    @Rrobinvip
    期待有时间与大佬多多交流。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3594 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 10:50 · PVG 18:50 · LAX 02:50 · JFK 05:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.