路径问题
路径问题

路径问题

1.目录 directory 与包package的区别

模块的定义:本质就是以 .py 结尾的python文件,模块的目的是为了其他程序进行引用。

目录(Dictionary):

Dictionary在pycharm中就是一个文件夹,放置资源文件,对应于在进行JavaWeb开发时用于放置css/js文件的目录,或者说在进行物体识别时,用来存储背景图像的文件夹。该文件夹其中并不包含__init.py__文件

包(Package):

对于Python package 文件夹而言,与Dictionary不同之处在于其会自动创建__init__.py文件。 简单的说,python package就是一个目录,其中包括一组模块和一个__init__.py文件。

2.导入模块

导入模块的方法:

import module_name
import module1_name, module2_name
from module_name import * #---> 一般import * 不建议使用
from module_name import m1,m2,m3  #---> m1为module_name下面的方法或变量
from module_name import logger as logger_a  #---> 为导入的变量或方法取个别名,引用时直接用别名

2.1 同级目录下模块的导入

img

main_day41.py中导入para_day41.py,两种方法:

# 方法一: 
# 相当于把 para_day41.py 中的所有代码拷贝过来赋值给变量 para_day41 ,引用时直接用 "该变量."

import para_day41

# 变量.xxx 调用
para_day41.show_para()

# 运行结果:
the para_day41
#方法二: 只把 para_day41.py 中 name 变量和 show_para 方法拷贝过来,可以直接用(推荐用该方法)

from para_day41 import name,show_para

print(name)
show_para()

运行结果:
D:\python365\python3.exe D:/Pyexample/20190220Day4/main_day41.py

para_day41
in the para_day41

2.2不同级目录下模块的导入:

(1)导入子目录下的模块

img

main.py 中导入 day51 目录下面 para_day51.py:

import day51.para_day51
day51.para_day51.show_para()

from day51.para_day51 import *
show_para()

from day51 import para_day51
para_day51.show_para()

运行结果:
D:\python365\python3.exe D:/Pyexample/20190220Day5/main.py
in the para_day51

(2)导入上级目录下的模块 --- 重要

img

day22 目录下面的 main_day22.py 导入 day21 目录下的 para_day21.py

注:执行 main_day22.py 时,要导入 day21 目录下的 para_day21.py,具体的搜索路径是这样的:

首先,python需要在当前目录下去找 para_day21.py,发现没有,然后就到 sys.path 列表中的每个路径下面去找:

['D:\\Pyexample\\20190220Day2\\day22', 'D:\\Pyexample', 'D:\\Pyexample\\W3', 'D:\\Pyexample\\20181113', 'D:\\Pyexample\\CSP\\cspmonitor', 'D:\\Pyexample\\python', 'D:\\python365\\python36.zip', 'D:\\python365\\DLLs', 'D:\\python365\\lib', 'D:\\python365', 'D:\\python365\\lib\\site-packages']

如果不在该列表中,则无法导入

(3)手动添加sys.path

import sys,os
p = os.path.dirname(                   # 上一级目录路径
        os.path.dirname(               # 本级目录路径
            os.path.abspath(__file__)  # 本级文件路径
        )
    )
sys.path.append(BASE_DIR)

这样就把上一级目录添加进来了,可以导入了。

(4)打印当前目录

os.getcwd()
# >>>''D:\\workspace\\爬虫文档整理\\08-软件谷oceanspider\\oceanspider'
os.path.abspath(os.curdir)
# >>>''D:\\workspace\\爬虫文档整理\\08-软件谷oceanspider\\oceanspider'
os.path.abspath('.')
# >>>''D:\\workspace\\爬虫文档整理\\08-软件谷oceanspider\\oceanspider'
sys.path[0]
# >>>''D:\\SoftwarePlace\\JetBrains\\PyCharm 2021.2.1\\plugins\\python\\helpers\\pydev'
sys.argv[0]
# >>>''D:\\SoftwarePlace\\JetBrains\\PyCharm 2021.2.1\\plugins\\python\\helpers\\pydev\\pydevconsole.py'
sys.argv
# >>>'['D:\\SoftwarePlace\\JetBrains\\PyCharm 2021.2.1\\plugins\\python\\helpers\\pydev\\pydevconsole.py', '--mode=client', '--port=55166']
sys.path
# >>>['D:\\SoftwarePlace\\JetBrains\\PyCharm 2021.2.1\\plugins\\python\\helpers\\pydev', 'D:\\SoftwarePlace\\JetBrains\\PyCharm 2021.2.1\\plugins\\python\\helpers\\pycharm_display', 'D:\\SoftwarePlace\\JetBrains\\PyCharm 2021.2.1\\plugins\\python\\helpers\\third_party\\thriftpy', 'D:\\SoftwarePlace\\JetBrains\\PyCharm 2021.2.1\\plugins\\python\\helpers\\pydev', 'C:\\Users\\Administrator\\Envs\\ocean\\Scripts\\python36.zip', 'd:\\softwareplace\\python3.6.6\\DLLs', 'd:\\softwareplace\\python3.6.6\\lib', 'd:\\softwareplace\\python3.6.6', 'C:\\Users\\Administrator\\Envs\\ocean', 'C:\\Users\\Administrator\\Envs\\ocean\\lib\\site-packages', 'D:\\SoftwarePlace\\JetBrains\\PyCharm 2021.2.1\\plugins\\python\\helpers\\pycharm_matplotlib_backend', 'D:\\workspace\\爬虫文档整理\\08-软件谷oceanspider\\oceanspider', 'D:\\workspace\\爬虫文档整理\\08-软件谷oceanspider\\oceanspider\\restback', 'D:/workspace/爬虫文档整理/08-软件谷oceanspider/oceanspider']

os.getcwd()、os.path.abspath(os.curdir)、os.path.abspath('.')在以上三种情况下的结果都是执行文件所在的目录

sys.argv[0]是当前执行的Python脚本的文件名,不一定是当前的路径。

sys.path[0]是当前系统环境变量的第一个值。当运行.py和以生成多文件模式打包的可执行文件时,输出结果是程序的当前目录。而由单文件模式打包生成的可执行文件,输出结果是系统的默认当前工作目录。

由于os.getcwd()、os.path.abspath(os.curdir)、os.path.abspath('.')是获取的当前python 的工作目录,而工作目录是可以通过os.chdir(path)更改的。

os.chdir(path):改变当前工作目录到指定路径path。

所以如果想要获取当前路径,最稳定的方法是:os.path.dirname(sys.argv[0])

三、导入包

导入包的本质就是执行这个包下面的init.py文件

1.同级路径下包的导入:

img

main.py中导入包day31,直接用import 包名即可

import day31 

(1)__init__.py中没有内容时

D:\python365\python3.exe D:/Pyexample/20190220Day3/main.py Process finished with exit code 0 

(2)__init__.py中有内容时:

img

D:\python365\python3.exe D:/Pyexample/20190220Day3/main.py 
in the day31 __init__ 

Process finished with exit code 0 

2.不同级路径下包的导入:

img

前提:需要将要导入的包所在的路径添加到 sys.path 列表中,方法同上,不再赘述。

3. 导入包中的模块

只是导入一个包并没有什么实际意义,包是用来从逻辑上组织模块的,所以实际项目中更多的是导入包中的模块,导入包中模块的方法:

from Package1 import Module1 
from Package1 import Package2 
from Package1.Module1 import m1,m2 # m1,m2为模块中的变量或方法 
from Package1.Module1 import * 
import Package1.Module1 
import Package1.Package2 

要导入的包及其模块结构如下:

img

(1)在main.py中导入包day31下面的para_day31.py或者para_day32.py模块

import day31.para_day31,day31.para_day32 
day31.para_day31.show_para() 
day31.para_day32.show_para() 
==========================================================
>>>运行结果: 
D:\python365\python3.exe D:/Pyexample/20190220Day3/main.py 
in the day31 __init__ 
in the para_day31 
in the para_day32 
Process finished with exit code 0 

或者:

from day31 import para_day31,para_day32 
para_day31.show_para() 
para_day32.show_para() 
============================================================
>>>运行结果: 
D:\python365\python3.exe D:/Pyexample/20190220Day3/main.py 
in the day31 __init__ 
in the para_day31 
in the para_day32 
Process finished with exit code 0 

或者:

from day31.para_day31 import show_para,name 
print(name) show_para() 
============================================================
>>>运行结果: 
D:\python365\python3.exe D:/Pyexample/20190220Day3/main.py 
in the day31 __init__ para_day31 
in the para_day31 
Process finished with exit code 0

或者:

from day31.para_day31 import * 
print(name) 
show_para() 

(2)在main.py中导入包day31下面所有的模块,即全部导入

from day31 import * 
para_day31.show_para() 
para_day32.show_para() 
============================================================
>>>运行结果: D:\python365\python3.exe D:/Pyexample/20190220Day3/main.py 
in the day31 __init__ 
Traceback (most recent call last):  
    File "D:/Pyexample/20190220Day3/main.py", line 35, in <module>    
    para_day31.show_para() 
NameError: name 'para_day31' is not defined 
Process finished with exit code 1

此时,需要用到__init__.py文件中的__all__变量,在day31包中的__init__.py文件中定义如下:

""" 
@Author:janson 
@Date:2019/2/20 
@File:__init__ 
""" 
print("in the day31 __init__") 
__all__ = ['para_day31','para_day32'] 

这时 from day31 import * 就会把注册在包__init__.py 文件中__all__列表中的子模块和子包导入到当前作用域中来:

再次运行就不会报错了:

from day31 import * 
para_day31.show_para() 
para_day32.show_para() 
============================================================
>>>运行结果: D:\python365\python3.exe D:/Pyexample/20190220Day3/main.py 
in the day31 __init__ in the para_day31 
in the para_day32 
Process finished with exit code 0

四. pycharm 工程目录结构写代码路径问题

pycharm 默认情况下只检索 项目根目录下的py文件,当引用的py文件不在项目根目录时,会出现错误,类似下边的情况:

image-20220111150053467

解决方法:

只需将要引用的py文件所在的文件夹添加到默认搜索搜索文件夹即可,具体有如下两种方法:

方法一 (推荐)

右键 py 文件所在的文件夹,依次点击:MarkDircetory as -> Sources Root即可。

image-20220111150132709

方法二

将py文件所在文件夹作为一个package,在py文件所在文件夹下新建_init_.py文件,在_init_.py中添加如下语句:

from [py文件所在文件夹名].[py文件名] import 模块名

image-20220111150353999

五. Python_PyCharm中引用同一目录下的模块

如下图,要在main.py中导入networks和manager两个模块;

image-20220111150539080

错误示例:

import networks as net    
from manager import Manager, Optimizers

原因: PyCharm工程当前目录在上一层,所以需要从目录开始引用

import src.networks as net      
# PyCharm工程当前目录在上一层,所以需要从目录开始引用 from src.manager import Manager, Optimizers

总结

image-20220111150847824

image-20220111150956908

简单的测试

image-20220111151052156

pycharm 中运行:

image-20220111151241775

image-20220111151359250

image-20220111151516374

保证可以 直接在当前目录下运行的时候, 也可以搜索到 其它的包, 不会报错

image-20220111151730220

实际部署的时候设置一个主路口文件, 可以参考django的目录设计

image-20220111151925304

image-20220111152020779




可以看到 在根目录中 导入需要运行的程序, 可以不用 添加父目录以及祖目录,

其实这种好的习惯, 也可以帮我们合理的规划项目

pycharm 这种 自动添加根目录的方式, 给很多小白带来了困惑



发表回复

您的电子邮箱地址不会被公开。