Python微信订餐小程序课程视频

https://edu.csdn.net/course/detail/36074

Python实战量化交易理财系统

https://edu.csdn.net/course/detail/35475

温馨提示: 本篇演示环境是Python 3.8

python --help看下python -m参数的解释:

-m mod : run library module as a script (terminates option list)

modmodule的缩写,即-m后面跟的是模块(module)名,意思是把模块当成脚本来运行。

terminates option list意味着-m之后的其它选项不起作用,在这点上它跟-c是类似,都是终极选项。

既然涉及到模块,这里就多提几句。 在Python中,一个.py文件就称之为一个模块(Module)。

比如一个顶层包名bytesfly,按照如下目录存放:

bytesfly
├─ __init__.py
├─ __main__.py
└─ fly.py

上面fly.py模块的名字就是bytesfly.fly

注意: 模块名是不带.py后缀的。

关于模块更详细的讲解见之前的博客:
https://blog.csdn.net/bytesfly/p/python.html#模块

python -m 常见用法

  • 使用cProfile模块分析程序函数调用链耗时
  • python -m cProfile -s cumulative bytesfly/fly.py
    
    
  • 使用pdb模块以调试模式来执行Python脚本
  • python -m pdb bytesfly/fly.py
    
    
  • 使用http.server模块实现一个简单的HTTP服务
  • python -m http.server 9000
    
    
  • 使用pydoc模块生成HTML格式的官方帮助文档,可以在浏览器中访问
  • python -m pydoc -p 9001
    
    
  • python -m pip install xxx
  • 在存在多个Python版本的环境中,这种写法可以精确地控制三方库的安装位置。例如用python3.8 -m pip,可以明确指定给3.8版本安装,而不会混淆成其它的版本。

    当然现在我们大多使用conda之类的虚拟环境管理器和包管理器,可能不会出现上面所说的这种混淆情况。这里只是提一下。

  • 使用timeit模块分析执行耗时
  • python -m timeit -n 3 -r 2 "import time;time.sleep(1)"
    
    

    其实调用的是:

    timeit.repeat("import time;time.sleep(1)", repeat=2, number=3)
    
    

    看一眼timeit.py中的源码就能快速理解-n -r参数的意思:

    def repeat(self, repeat=default\_repeat, number=default\_number):
        """Call timeit() a few times.
    
     This is a convenience function that calls the timeit()
     repeatedly, returning a list of results. The first argument
     specifies how many times to call timeit(), defaulting to 5;
     the second argument specifies the timer argument, defaulting
     to one million.
     """
        r = []
        for i in range(repeat):
            t = self.timeit(number)
            r.append(t)
        return r
    
    

    -p/–process: use time.process_time() (default is time.perf_counter())

    timeit后面还能添加-p参数,如下:

    python -m timeit -p -n 3 -r 2 "import time;time.sleep(1)"
    
    

    其实调用的是:

    timeit.repeat("import time;time.sleep(1)", repeat=2, number=3, timer=time.process_time)
    
    

    再看一眼time.process_time()的代码注释

    def process\_time(): # real signature unknown; restored from \_\_doc\_\_
        """
     process\_time() -> float
     
     Process time for profiling: sum of the kernel and user-space CPU time.
     """
        return 0.0
    
    

    加上了-p参数计算的是sum of the kernel and user-space CPU time,讲白了就是程序占用CPU的时间,程序睡眠或者请求网络IO阻塞的时间不算。

    python -m 原理解析

    看了上面python -m几种常见用法,你是否好奇python -m到底做了什么事?

    不卖关子,一句话解释就是:

    对于python -m module_name,Python会检索sys.path,查找名字为module_name的模块或者包,并将其内容当成主程序入口来执行,换句话说在执行时,该脚本的__name____main__

    拿文章开篇的bytesfly.fly模块来说,也就是bytesfly包下的fly.py文件内容如下:

    import sys
    
    print("----fly----")
    
    if __name__ == '\_\_main\_\_':
        print("fly\_main")
        print(sys.path)
    
    

    hello项目路径下执行python -m bytesfly.fly,输出如下:

    ----fly----
    fly_main
    ['/home/bytesfly/py/hello', '/home/bytesfly/anaconda3/envs/test/lib/python38.zip']
    
    

    如果直接执行呢? 即相同路径下执行python bytesfly/fly.py,输出如下:

    ----fly----
    fly_main
    ['/home/bytesfly/py/hello/bytesfly', '/home/bytesfly/anaconda3/envs/test/lib/python38.zip']
    
    

    总结一下,python -m module_namepython folder/file.py,都会把定位到的Python脚本当成主程序入口来执行,即在执行时,该脚本的__name__都是__main__,与import导入模块不同。

    但是有注意到上面两种调用方式的不同之处吗?

    fly.py程序输出了sys.path,可以看到两种调用方式的Python Path有区别,这种区别有什么影响呢?

    再看一个例子。 比如一个顶层包名还是bytesfly,按照如下目录存放:

    bytesfly
    ├─ __init__.py
    ├─ __main__.py
    └─ fly.py
    └─ a
       ├─ __init__.py
       └─ run.py
    └─ b
       ├─ __init__.py
       └─ tool.py
    
    

    其中tool.py内容如下:

    def add(a, b):
        return a + b
    
    

    其中run.py内容如下:

    import sys
    
    print(sys.path)
    
    if __name__ == '\_\_main\_\_':
        from bytesfly.b import tool
    
        print(tool.add(1, 2))
    
    

    同样在hello项目路径下执行python -m bytesfly.a.run,输出如下:

    ['/home/bytesfly/py/hello', '/home/bytesfly/anaconda3/envs/test/lib/python38.zip']
    3
    
    

    然后在hello项目路径下执行python bytesfly/a/run.py,输出如下:

    ['/home/bytesfly/py/hello/bytesfly/a', '/home/bytesfly/anaconda3/envs/test/lib/python38.zip']
    Traceback (most recent call last):
      File "bytesfly/a/run.py", line 6, in 
     from bytesfly.b import tool
    ModuleNotFoundError: No module named 'bytesfly'
    
    

    这个地方能Get到这两种调用方式在Python Path上的区别?

    除此之外,python -m module_namepython folder/file.py,在实现上有什么不同呢?

  • 使用python -m module_name,解释器在不import模块的情况下,在所有模块命名空间中查找,定位到脚本的路径,然后执行。为了实现这个过程,解释器会借助两个模块:pkgutilrunpy,前者用于获取所有的模块列表,后者根据模块名来定位并执行脚本
  • 直接运行脚本时,相当于给出了脚本的完整路径(不管是绝对路径还是相对路径),解释器根据文件系统的查找机制,定位到该脚本,然后执行
  • python -m 补充说明

    python -m module_name这里的module_name也可以是包名。

    还是用上面的顶层包名bytesfly举例,按照如下目录存放:

    bytesfly
    ├─ __init__.py
    ├─ __main__.py
    └─ fly.py
    └─ a
       ├─ __init__.py
       └─ run.py
    └─ b
       ├─ __init__.py
       └─ tool.py
    
    

    其中__main__.py内容如下:

    import sys
    
    print("---bytesfly---")
    
    if __name__ == '\_\_main\_\_':
        print(sys.path)
    
    

    项目路径下执行python -m bytesfly,输出如下:

    ---bytesfly---
    ['/home/bytesfly/py/hello', '/home/bytesfly/anaconda3/envs/test/lib/python38.zip']
    
    

    如果执行python -m bytesfly.a,输出如下:

    No module named bytesfly.a.__main__; 'bytesfly.a' is a package and cannot be directly executed
    
    

    原来,python -m bytesfly等效于python -m bytesfly.__main__

    写在最后

    有了python -m module_name选项,在命令行中使用内置模块、标准包与第三方模块更加方便。

    参考:

    https://blog.csdn.net/pythonista/p/11829632.html

    https://blog.csdn.net/xueweihan/p/5118222.html

    来源:洛蕾

    物联沃分享整理
    物联沃-IOTWORD物联网 » python -m详解

    发表评论