• python relative import and python m flag


    absolute import

    https://realpython.com/absolute-vs-relative-python-imports/#absolute-imports

    从项目根目录开始, 使用绝对路径 查找 package 或者 module

    An absolute import specifies the resource to be imported using its full path from the project’s root folder.

    └── project
        ├── package1
        │   ├── module1.py
        │   └── module2.py
        └── package2
            ├── __init__.py
            ├── module3.py
            ├── module4.py
            └── subpackage1
                └── module5.py

    Let’s assume the following:

    1. package1/module2.py contains a function, function1.
    2. package2/__init__.py contains a class, class1.
    3. package2/subpackage1/module5.py contains a function, function2.

    The following are practical examples of absolute imports:

    from package1 import module1
    from package1.module2 import function1
    from package2 import class1
    from package2.subpackage1.module5 import function2

    优点: 明确,直接。

    Pros and Cons of Absolute Imports

    Absolute imports are preferred because they are quite clear and straightforward. It is easy to tell exactly where the imported resource is, just by looking at the statement. Additionally, absolute imports remain valid even if the current location of the import statement changes. In fact, PEP 8 explicitly recommends absolute imports.

    缺点: 冗长。

    Sometimes, however, absolute imports can get quite verbose, depending on the complexity of the directory structure. Imagine having a statement like this:

    from package1.subpackage2.subpackage3.subpackage4.module5 import function6
    

    That’s ridiculous, right? Luckily, relative imports are a good alternative in such cases!

    relative import

    https://realpython.com/absolute-vs-relative-python-imports/#relative-imports

    A relative import specifies the resource to be imported relative to the current location—that is, the location where the import statement is. There are two types of relative imports: implicit and explicit. Implicit relative imports have been deprecated in Python 3, so I won’t be covering them here.

    └── project
        ├── package1
        │   ├── module1.py
        │   └── module2.py
        └── package2
            ├── __init__.py
            ├── module3.py
            ├── module4.py
            └── subpackage1
                └── module5.py

    Recall the file contents:

    1. package1/module2.py contains a function, function1.
    2. package2/__init__.py contains a class, class1.
    3. package2/subpackage1/module5.py contains a function, function2.

    You can import function1 into the package1/module1.py file this way:

    # package1/module1.py
    
    from .module2 import function1
    
    
    # package2/module3.py
    
    from . import class1
    from .subpackage1.module5 import function2

    优点:简洁

    缺点:隐晦

    Pros and Cons of Relative Imports

    One clear advantage of relative imports is that they are quite succinct. Depending on the current location, they can turn the ridiculously long import statement you saw earlier to something as simple as this:

    from ..subpackage4.module5 import function6
    

    Unfortunately, relative imports can be messy, particularly for shared projects where directory structure is likely to change. Relative imports are also not as readable as absolute ones, and it’s not easy to tell the location of the imported resources.

    相对导入不能在顶级模块中使用

    https://zhuanlan.zhihu.com/p/145903888

    现象

    最常见的就是 ModuleNotFoundError: No module named 'moduleY'ValueError: attempted relative import beyond top-level packageModuleNotFoundError: No module named '__main__.moduleY'; '__main__' is not a package等这些异常

    使用了相对导入的模块文件不能作为顶层执行文件

    对于下面moduleX.py 的代码,执行 python moduleX.py 将会引发 ModuleNotFoundError: No module named '__main__.moduleY'; '__main__' is not a package 异常。

    # moduleX.py
    from .moduleY import *

    原理

    相对寻址,使用__name__(模块全路径) 作为寻址依据。

    而顶层模块,就是被python解析器直接运行的文件,

    在此文件内 __name__ 被赋值为 __main__ 字符串,

    此字符串并能作为全路径。

    Relative imports use a module's __name__attribute to determine that module's position in the package hierarchy. If the module's name does not contain any package information (e.g. it is set to '__main__') then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.

    实际上, 相对寻址, 还直接依赖另外一个魔法变量 __package__,

    当__name__不为 __main__ 时候, 会构给 __package__ 赋值为 dirname(__name__)

    否则, __package__ = None

    实例

    package/
        __init__.py
        subpackage1/
            __init__.py
            moduleX.py
            moduleY.py
        subpackage2/
            __init__.py
            moduleZ.py
        moduleA.py
    # moduleA.py
    print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))
    ​
    from subpackage2 import moduleZ
    # moduleZ.py
    print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))

    python moduleA.py

    __file__=D:/top/package/moduleA.py | __name__=__main__             | __package__=None                
    __file__=D:\top\package\subpackage2\moduleZ.py | __name__=subpackage2.moduleZ  | __package__=subpackage2         

    python -m 解决上面问题

    https://zhuanlan.zhihu.com/p/91120727

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

    python -m xx.yy

    其中 xx.yy 为 import使用的模块全路径

    这里寻址方式也跟import一致

    如果yy对应文件 yy.py, 则直接执行此文件;

    如果yy对应一个package, 则查找包下的 __main__.py 并执行。

    对于上面两部的执行的文件, 在这两个文件中, 虽然 __name__ 都是 __main__ , 但是 __package__ 被赋值为 “” , 而不是 None, 这表示其支持了相对寻址方式。

    "mod"是“module”的缩写,即“-m”选项后面的内容是 module(模块),其作用是把模块当成脚本来运行。

    -m 选项的五个典型用法

    Python 中有很多使用 -m 选项的场景,相信大家可能会用到或者看见过,我在这里想分享 5 个。

    在 Python3 中,只需一行命令就能实现一个简单的 HTTP 服务:

      python -m http.server 8000
      # 注:在 Python2 中是这样
      python -m SimpleHTTPServer 8000

    已知一个模块的名字,但不知道它的文件路径,那么使用“-m”就意味着交给解释器自行查找,若找到,则当成脚本执行。

    那么,“-m”方式与直接运行脚本相比,在实现上有什么不同呢?

    • 直接运行脚本时,相当于给出了脚本的完整路径(不管是绝对路径还是相对路径),解释器根据文件系统的查找机制, 定位到该脚本,然后执行
    • 使用“-m”方式时,解释器需要在不 import 的情况下,在所有模块命名空间 中查找,定位到脚本的路径,然后执行。为了实现这个过程,解释器会借助两个模块:pkgutilrunpy ,前者用来获取所有的模块列表,后者根据模块名来定位并执行脚本
    • 如果“-m”之后要执行的是一个包,那么解释器经过前面提到的查找过程,先定位到该包,然后会去执行它的“__main__”子模块,也就是说,在包目录下需要实现一个“__main__.py”文件。

    实例

    https://stackoverflow.com/questions/21233229/whats-the-purpose-of-the-package-attribute-in-python

    All I want to know is what exactly does __package__ mean

    It is the mechanism that enables explicit relative imports.

    There are three possible categories of values for __package__

    • A package name (a string)
    • An empty string
    • None

    Package Name

    That is, if a module is in a package, __package__ is set to the package name to enable explicit relative imports. Specifically:

    When the module is a package, its __package__ value should be set to its __name__. When the module is not a package, __package__ should be set [...] for submodules, to the parent package’s name.

    Empty String

    If a module is at root, or top-level, that is, the current module is imported with

    import current_module
    

    or when a top-level module is run as the entry point as with:

    $ python -m current_module
    

    then __package__ is an empty string. Or as the documentation says:

    When the module is not a package, __package__ should be set to the empty string for top-level modules...

    None

    If a module/script is run by filename, __package__ is None:

    When the main module is specified by its filename, then the __package__ attribute will be set to None.

    Evidence

    First, let's create a file structure with noisy debugging - using Python 3.6:

    text = "print(f'{__name__}, __file__: {__file__}, __package__: {repr(__package__)}')"
    
    from pathlib import Path
    Path('foo.py').write_text(text)
    Path('package').mkdir()
    Path('package/__init__.py').write_text(text)
    Path('package/__main__.py').write_text(text)
    Path('package/bar.py').write_text(text)
    
    # and include a submodule with a relative import:
    Path('package/baz.py').write_text(text + '\nfrom . import bar')
    

    Now we see that foo.py executed as a module has an empty string for __package__, while the script executed by file name as the entry point has None:

    $ python -m foo
    __main__, __file__: ~\foo.py, __package__: ''
    $ python foo.py
    __main__, __file__: foo.py, __package__: None
    

    When we execute a package as a module for the entry point, its __init__.py module runs, then its __main__.py runs:

    $ python -m package
    package, __file__: ~\package\__init__.py, __package__: 'package'
    __main__, __file__: ~\package\__main__.py, __package__: 'package'
    

    Similarly, when we execute a submodule as a module for the entry point, the __init__.py module runs, then it runs:

    $ python -m package.bar
    package, __file__: ~\package\__init__.py, __package__: 'package'
    __main__, __file__: ~\package\bar.py, __package__: 'package'
    

    Finally, we see that the explicit relative import, the entire reason for having __package__, (which happens last here) is enabled:

    $ python -m package.baz
    package, __file__: ~\package\__init__.py, __package__: 'package'
    __main__, __file__: ~\package\baz.py, __package__: 'package'
    package.bar, __file__: ~\package\bar.py, __package__: 'package'
    

    Note, in the output, I have substituted ~ for the parent directories.

    python -m pip install 必要性

    https://snarky.ca/why-you-should-use-python-m-pip/

    当有多个python版本安装在同一台环境上, 那么 pip install是对哪一个 python版本生效不得而知。

    如果使用 python -m pip install 则可以指定python版本。

    What is python -m pip?

    To begin with, python -m pip executes pip using the Python interpreter you specified as python. So /usr/bin/python3.7 -m pip means you are executing pip for your interpreter located at /usr/bin/python3.7. You can read the docs on -m if you're unfamiliar with the flag and how it works (it's very handy).

    Why use python -m pip over pip/pip3?

    But when you use python -m pip with python being the specific interpreter you want to use, all of the above ambiguity is gone. If I say python3.8 -m pip then I know pip will be using and installing for my Python 3.8 interpreter (same goes for if I had said python3.7).

  • 相关阅读:
    夺命雷公狗---PDO NO:9 使用PDO准备语句并执行语句3
    夺命雷公狗---PDO NO:9 使用PDO准备语句并执行语句2
    [LeetCode] Lowest Common Ancestor of a Binary Search Tree
    二叉树
    LeetCode Palindrome LinkList
    LeetCode Same Tree
    LeetCode Merge Sorted List
    LeetCode Remove Duplicated from Sorted List
    LeetCode Climbing Stairs
    LeetCode Count And Say
  • 原文地址:https://www.cnblogs.com/lightsong/p/15904437.html
Copyright © 2020-2023  润新知