• 2019python面试题-模块加载顺序


    Python 解释器是如何查找包和模块的

    Python 执行一个 py 文件,无论执行的方式是用绝对路径还是相对路径,interpreter 都会把文件所在的 directory 加入 sys.path 这个 list 中,并且是索引为 0 的位置。Python 就是在 sys.path 中查找包和模块的。

    sys.modules 的作用

    载入的模块存放在何处? 答案是 sys.modules。 模块一经载入, Python 会把这个模块加入 sys.modules 中供下次载入使用,这样可以加速模块引入,起到缓存作用。sys.modules 是一个 dict 类型的值。python中的全局module集合sys.modules被称为modules缓存,保证了module的唯一性,每当有import操作都会在该sys.modules查找,如果不存在就会将该module加入到sys.modules中。

    解释器查找包:

    • 解释器会默认加载一些 modules,除了sys.builtin_module_names 列出的内置模块之外,还会加载其他一些标准库,都存放在sys.modules字典中。sys.modules 包含了所有加载的模块。 import 语句在实际从磁盘上加载模块之前,会先去检查这个字典!*注:内置模块不是标准库,是指 sys.builtin_module_names输出的字符串元组。解释器启动时确实会加载buit-in module,但是,执行print(sys.builtin_module_names)发现,os并不是built-in module。所以,解释器执行 python 文件时,不仅仅是加载了内置模块的!!!使用sys.modules可以看到实际启动时加载的所有模块。
    • 然后就是搜索 sys.path 路径下的模块了。
    import sys
    
    print(sys.builtin_module_names)
    
    运行结果:
    ('_abc', '_ast', '_codecs', '_collections', '_functools', '_imp', '_io', '_locale', '_operator', '_signal', '_sre', '_stat', '_string', '_symtable', '_thread', '_tracemalloc', '_warnings', '_weakref', 'atexit', 'builtins', 'errno', 'faulthandler', 'gc', 'itertools', 'marshal', 'posix', 'pwd', 'sys', 'time', 'xxsubtype', 'zipimport')

    这样的查找顺序将会导致同名包或模块被遮蔽(如下):

    # tree
    $ tree . -L 1
    .
    ├── __init__.py
    ├── name
    ├── os.py
    ├── test2.py
    ├── test.py
    └── test.pyc
    
    # test2.py
    import os
    from redis import Redis
    from test import hello
    
    print('Now in test2.py')
    print(os.getcwd())
    
    # 执行 python test2.py
    $ python test2.py
    Traceback (most recent call last):
      File "test2.py", line 2, in <module>
        from redis import Redis
    ImportError: No module named redis

    这里的 os 模块并不是 built-in module的,上面已经将 sys.builtin_module_names 内容打印出来了。只是 Python 解释器启动时就加载到了 sys.modules中缓存起来了。所以,即使在同目录下有同名模块,解释器依然是可以找到正确的 os 模块的(sys.modules中的os模块)!如果你在import os之前,先执行del sys.modules['os'],那么,标准模块 os 就会被同目录下的 os.py 屏蔽了。

    *注:del删除模块只是把模块从当前命名空间中删除,但该module依然存在于module缓存中。

    redis 属于第三方模块,默认安装位置是 Python 环境变量中的 site-packages,解释器启动之后,会将此目录加到 sys.path,由于当前目录会在 sys.path 的首位,当前目录的 redis 优先被找到了,site-packages 中的 redis 模块被屏蔽了。

    综上所述,搜索的一个顺序是:sys.modules 缓存 -> sys.path[0] 即当前目录查找 -> sys.path[1:]路径查找。

    *注:同时发现,模块被加载的时候,其中非函数或类的语句,例如 print('hello')name=michael等,是会在 import的时候,默认就执行了。

     

  • 相关阅读:
    vuejs开发环境搭建
    贝塞尔曲线(cubic bezier)
    解决安装mysql的”A Windows service with the name MySQL already exists.“问题
    display:inline-block的间隙问题和解决办法
    限制两行显示,超出部分省略号
    border-radius四个值的问题
    PHP环境搭建
    CSS3属性box-sizing
    -webkit-tap-highlight-color
    gdb命令
  • 原文地址:https://www.cnblogs.com/yekushi-Z/p/11477985.html
Copyright © 2020-2023  润新知