python路径sys.path,导入,包,模块

包与模块和普通文件夹

模块

1个py文件是一个模块,一个包,一个文件夹也可以叫做模块,验证:

python路径sys.path,导入,包,模块_第1张图片
import torch
import numpy as np
import test_package
from test_package.test_son  import son_py
import test_package.test_son
son_py.hello()
print(test_package.test_son)
print(test_package)

直接子目录里面有__init__.py的文件夹(孙目录不行)

包中的init.py

init.py

永远和包一对一绑定,调用包时执行的文件

比如导入A包下的a1.py

from A import a1

执行A的__init__.py再执行a1.py

文件夹:就是不含__init__.py

包和文件夹的区别:

就只有__init__.py的区别,其他我觉得完全没有区别,如上代码,都是模块,都可以作为模块导入。

import

导入加载顺序

from package_A import module_B/package_B中,先执行的是package_A中的__init__.py文件,再执行后面的module_B文件或者package_B中的__init__.py文件。

主要作用

将模块或函数导入到我选定的文件之中。

导入了什么包,import就会执行啥

最简单的情况:A导入了B,如果B是模块,那么会在A执行到import B的地方去执行B模块中的所有代码(已验证)(但是其他执行过的语句、变量、函数除了他import规定的,其他的是看不到的)(不设置全局的代码一般不会耗费太多时间,不管你是只导入了B中的一个变量还是一个函数,都会执行完所有代码),需要注意执行时模块/包 内代码变量都是独立的,也就是并不是简单的我把B的代码接在A之前,之前有过这种理解,是不准确的。

验证红字:

主文件

import torch
import numpy as np
from test_package.hello  import hello
python路径sys.path,导入,包,模块_第2张图片

hello.py

def hello():
    print('hello')

print('hello py 其他部分被執行了')
hello py 其他部分被執行了

一个模块导入了其他的某个模块、函数,那么被导入的模块、函数就归该模块所有

结构

python路径sys.path,导入,包,模块_第3张图片

son_py.py

from ..hello import hello_func
from .. import hello
def test():
    hello()

hello.py

def hello_func():
    print('hello')

test_tensor.py--主函数

import torch
import numpy as np
import test_package.test_son.son_py as son_py
son_py.hello.hello_func()
son_py.hello_func()

可以看到son_py中并没有hello和hello_func,但因为其引入import了,可以认为son_py获得了hello和hello_func,归该块所有,所以可以使用。但hello.py中如果定义全局的变量a=1,主函数使用son_py.a是调用不到的,使用son_py.hello.a可以调用到。

导入的三种方式

import ,import as

可以导入包和模块,并且重命名

from 。。。import

万能,导入模块,包 ,导入 函数,变量,类(注意不是方法也不是成员变量,意思是不是类里面的东西)

判断用哪个可以根据要导入的类型来使用不同的代码

__name__ 与__main__

import testMoudel
print(__name__)
python路径sys.path,导入,包,模块_第4张图片
python路径sys.path,导入,包,模块_第5张图片

编辑

__name__就是模块名,主模块的__name__是__main__要注意主模块就是python XXX最开始执行的模块,其他的模块__name__是文件名,比如我A是主模块,A里调用了B,B里又import了A,那么第二次调用的A亲测他不是主模块。

去哪找包-sys.path

sys.path

简介

sys.path在每次调用python命令执行代码时自动生成,且只会生成一次

比如python xxx.py

sys.path提供了包的搜索路径,sys.path一般包括

  • 运行脚本所在的目录,也就是运行py文件的父目录(如果以模块运行则是当前目录)

  • PYTHONPATH 环境变量(类似于 PATH 变量,也是一组目录名组成)

可以由

echo $PYTHONPATH

通常执行结果为空

我们如果要指定动态指定PYTHONPATH,可以添加环境变量

export PYTHONPATH=./

可以做到在每次执行是都将调用python的当前路径加入到sys.path中,当我们(比如在项目文件夹)调用非当前文件夹下的tool/train.py,可以将项目根路径加进去path,就可以调用根路径的模块,非常好用。

  • Python 安装时的默认设置

生成的path在site.py可以看到

我们可以调用

python -m site

来实现查看sys.path,这个path去掉第一个当前路径就是我们的sys.path通常是如何生成的。

sys.path = [
    '/home/RAID0/zxy/code/point-transformer',
    '/home/RAID0/zxy/.conda/envs/pointTrans/lib/python37.zip',
    '/home/RAID0/zxy/.conda/envs/pointTrans/lib/python3.7',
    '/home/RAID0/zxy/.conda/envs/pointTrans/lib/python3.7/lib-dynload',
    '/home/RAID0/zxy/.conda/envs/pointTrans/lib/python3.7/site-packages',
    '/home/RAID0/zxy/.conda/envs/pointTrans/lib/python3.7/site-packages/pointops-0.0.0-py3.7-linux-x86_64.egg',
]

如图第一个是运行脚本所在的目录的path,后五个是安装位置,因为PYTHONPATH在此时我没有设置,为空,所以没有PYTHONPATH添加进来的path

sys.path也反映了找包优先级的问题,最上面的优先级最高

sys.path应该是在运行程序时会定下来(会调用site.py一次),这次运行程序结束之前都不会再改变了,并不是说我sys.path会随着当前所在执行文件的所在目录而随意跳动,因此可以看到别人写的包的模块中调用自己包内的包和模块会使用相对引用来实现。

如何使用pycharm运行模块?(python -m)

python路径sys.path,导入,包,模块_第6张图片
python路径sys.path,导入,包,模块_第7张图片

编辑

这里有个很小的下三角,点开后再配置就好了,记得修改工作目录为你想运行的位置

注意系统路径和执行路径:

sys.path.append('../../BADet-master')
python路径sys.path,导入,包,模块_第8张图片

像这种代码在不同地方执行得到的path是不一样的,比如我有一个文件 a/b/c/test.py里面有上面的这个语句,我在c文件夹内执行

python test.py
python路径sys.path,导入,包,模块_第9张图片

那么得到的是a/b/c->a路径,加入的path是a/BADet-master

如果我再a文件夹执行

python a/b/c/test.py
python路径sys.path,导入,包,模块_第10张图片

那加入的路径将是 ../../a/b/c的这个路径的BADet-master,都是取决于最终在哪个路径执行的

结论:python中有系统路径(sys.path)和执行路径之说,系统路径是执行时就创建好的也就是sys.path,执行路径是你在运行此代码时终端的位置(pythn a.py此时你终端所处的pwd就是执行路径),除了import找包,其他的搜索比如寻找某一个bin文件,搜寻数据集都是从执行路径来寻找的,系统路径可以包括当前执行路径,就是在使用-m的参数下,或者在py文件的父目录执行代码,也可以做到系统路径和执行路径统一的目的。在py文件内查找路径时都是以执行路径进行查找的。

例如:

执行路径为/home/RAID0/zxy/code/SIENet/tools

该py文件所在路径 /home/RAID0/zxy/code/SIENet/pcdet/datasets/augmentor/database_sampler.py

self.root_path='../data/kitti'

我执行

self.root_path.resolve()
python路径sys.path,导入,包,模块_第11张图片

得到的绝对路径步骤 :当然都是在执行路径的基础上得绝对路径

先去掉../得到 /home/RAID0/zxy/code/SIENet 还剩data/kitti

再将data/kitti进行拼接,得/home/RAID0/zxy/code/SIENet/data/kitti

path.resolve:方法会把一个路径或路径片段的序列解析为一个绝对路径。相当于先cd命令,再与执行路径进行拼接得绝对路径,直接调用resolve()则直接跳到与执行路径进行拼接得绝对路径。

相对导入

from . import grok
from .dataset import DatasetTemplate
python路径sys.path,导入,包,模块_第12张图片

1表示当前目录

2表示当前目录dataset下的Data。。。。

相对导入格式中:每多一个点,表示更上一层目录,需要注意相对导入不能超过顶级包的界限

相对导入

相对导入,如果是入口文件那么不能使用相对路径,就是python 1.py,那么1.py不能使用相对导入,非入口文件可以随意使用相对导入,比如1.py中调用2.py,2.py就能用。

绝对导入与相对导入的区别

  1. -m属性执行可以在任何地方执行sys.path中的代码,因为他执行的是模块,模块的话只要在sys.path中就能找到并执行,如果是普通执行则只能执行当前文件夹,或指定路径的py文件。

  1. -m属性添加到sys.path的是执行脚本时的路径加入到path,普通是添加py文件的父文件夹

Python模块__all__变量以及导入可见性问题

需求:导入一个模块的所有变量,函数时,想选择性的允许外部导入自己的模块,有的可以让外部导入,有的我们不想让外部导入,此时用__all__可以做到

作用:唯一限制from demo import *能导入的东西(注意只能限制这一种方式)

事实上,当我们向文件导入某个模块时,导入的是该模块中那些名称不以下划线(单下划线“_”或者双下划线“__”)开头的变量、函数和类。因此,如果我们不想模块文件中的某个成员被引入到其它文件中使用,可以在其名称前添加下划线。

以前面章节中创建的 demo.py 模块文件和 test.py 文件为例(它们位于同一目录),各自包含的内容如下所示:

#demo.py
def say():
    print("人生苦短,我学Python!")
def CLanguage():
    print("C语言中文网:http://c.biancheng.net")
def disPython():
    print("Python教程:http://c.biancheng.net/python")

#test.py
from demo import *
say()
CLanguage()
disPython()

执行 test.py 文件,输出结果为:

人生苦短,我学Python!
C语言中文网: http://c.biancheng.net
Python教程: http://c.biancheng.net/python

在此基础上,如果 demo.py 模块中的 disPython() 函数不想让其它文件引入,则只需将其名称改为 _disPython() 或者 __disPython()。修改之后,再次执行 test.py,其输出结果为:

人生苦短,我学Python!
C语言中文网: http://c.biancheng.net
Traceback (most recent call last):
File "C:/Users/mengma/Desktop/2.py", line 4, in
disPython()
NameError: name 'disPython' is not defined

显然,test.py 文件中无法使用未引入的 disPython() 函数。

Python模块__all__变量

除此之外,还可以借助模块提供的 __all__ 变量,该变量的值是一个列表,存储的是当前模块中一些成员(变量、函数或者类)的名称。通过在模块文件中设置 __all__ 变量,当其它文件以“from 模块名 import *”的形式导入该模块时,该文件中只能使用 __all__ 列表中指定的成员。

也就是说,只有以“from 模块名 import *”形式导入的模块,当该模块设有 __all__ 变量时,只能导入该变量指定的成员,未指定的成员是无法导入的。

举个例子,修改 demo.py 模块文件中的代码:

def say():
    print("人生苦短,我学Python!")
def CLanguage():
    print("C语言中文网:http://c.biancheng.net")
def disPython():
    print("Python教程:http://c.biancheng.net/python")
__all__ = ["say","CLanguage"]

可见,__all__ 变量只包含 say() 和 CLanguage() 的函数名,不包含 disPython() 函数的名称。此时直接执行 test.py 文件,其执行结果为:

人生苦短,我学Python!
C语言中文网: http://c.biancheng.net
Traceback (most recent call last):
File "C:/Users/mengma/Desktop/2.py", line 4, in
disPython()
NameError: name 'disPython' is not defined

显然,对于 test.py 文件来说,demo.py 模块中的 disPython() 函数是未引入,这样调用是非法的。

再次声明,__all__ 变量仅限于在其它文件中以“from 模块名 import *”的方式引入。也就是说,如果使用以下 2 种方式引入模块,则 __all__ 变量的设置是无效的。

1) 以“import 模块名”的形式导入模块。通过该方式导入模块后,总可以通过模块名前缀(如果为模块指定了别名,则可以使用模快的别名作为前缀)来调用模块内的所有成员(除了以下划线开头命名的成员)。

仍以 demo.py 模块文件和 test.py 文件为例,修改它们的代码如下所示:

#demo.py
def say():
    print("人生苦短,我学Python!")
def CLanguage():
    print("C语言中文网:http://c.biancheng.net")
def disPython():
    print("Python教程:http://c.biancheng.net/python")
__all__ = ["say"]
#test.py
import demo
demo.say()
demo.CLanguage()
demo.disPython()

运行 test.py 文件,其输出结果为:

人生苦短,我学Python!
C语言中文网: http://c.biancheng.net
Python教程: http://c.biancheng.net/python

可以看到,虽然 demo.py 模块文件中设置有 __all__ 变量,但是当以“import demo”的方式引入后,__all__ 变量将不起作用。

2) 以“from 模块名 import 成员”的形式直接导入指定成员。使用此方式导入的模块,__all__ 变量即便设置,也形同虚设。

仍以 demo.py 和 test.py 为例,修改 test.py 文件中的代码,如下所示:

from demo import say
from demo import CLanguage
from demo import disPython
say()
CLanguage()
disPython()

运行 test.py,输出结果为:

人生苦短,我学Python!
C语言中文网: http://c.biancheng.net
Python教程: http://c.biancheng.net/python

你可能感兴趣的:(python,python,pycharm,开发语言)