native.loadlibrary获取路径不对_【Python专题(三)】Python模块导入与路径管理

6b70bf19b43baeaff211711365887fc7.png

前言

Python项目的路径管理是一个让人头疼的问题。在写python项目的时候,明明 import了文件A,代码运行时却收到 ModuleNotFoundError,仔细一看,是引用路径不对,很是气人。又或者,当项目中出现了重名的packages时,发现引用的函数并不是自己想要的,而是其他同名packages中的函数。这些问题归根结底都是Python路径管理的问题。那么今天我们一起来看看Python的路径管理到底是怎么做的,了解原理后,以后自然不会被路径问题所困扰了!

路径索引顺序

如我们在Python专题(二)Python二三事中讲的,Python2和Python3在路径索引的顺序上有些许不同,感兴趣的同学可以参考上篇专题内容。本文仅讲Python3版本的情况。首先,在Python中有内建函数(built-in)、第三方库(site-packages)以及自义库三种可以 import的模块。然后,在 import模块时,Python解释器的搜索顺序是先搜索built-in模块,然后搜索 sys.path这个路径列表中的模块。那么Python的built-in模块又有哪些呢?我们可以在Python中用如下命令查看:

import sys
print(sys.builtin_module_names)

你会看到一长串builtin模块的名字,这些模块名称是 import动作最先搜索到的。

我们在来看看sys.path中又有哪些东西呢?

sys.path是一个路径列表,里面保存了解释器可以索引的所有路径。这个路径列表可分为如下部分:

  • 当前脚本路径
  • PYTHONPATH路径
  • 虚拟环境路径
  • site-packages路径

一般来说,第三方库会安装在site-packages路径下,当前脚本路径则是一些自定义模块,而PYTHONPATH和虚拟环境路径则是当前系统的环境变量和Python虚拟环境保存的路径。

所以当来了一个 import命令时,Python解释器的搜索顺序就是:

abb279912fbc350825e5b3c6db8f3c10.png

当然,这个sys.path中的索引顺序只是一个默认顺序,你完全可以在代码中通过sys模块修改这个顺序,在后文中你会看到如何对这个索引顺序进行修改。当完成 import动作后,Python会把这些模块的名字和所在路径保存在一个字典里,相当于一个缓存,在后面需要运行这个模块代码时可以迅速查找到该部分代码。你可以通过 print(sys.modules)来查看当前Python解释器缓存(导入)了哪些模块。

from 和 import

老生常谈的话题了,但是很容易忽略。多数情况下,

from module import fun
a = fun()

import module
a = module.fun()

在效果上是等价的。区别是第一种方式只引用了 module中的 fun函数,而第二种方式引用了整个 module。只引用 fun函数,可能造成代码中的变量名混乱,譬如你的代码中本来就有一个名为 fun的函数,这时候用第一种方式导入,会悄无声息地替换掉代码中原本的 fun函数,从而引起命名空间混乱。而引用整个 module时,解释器会运行 module中的所有代码,如果 module中有很耗时而我们又不需要的运算,第二种方式会存在冗余资源消耗。

还有一种导入模块的方式:

from module import *
a = fun()

这种导入模块的方式是官方不提倡的,因为刚才们提到用 fromimport的方法会产生变量名混乱,但是 frommoduleimportfun毕竟还是指定了导入的函数名,开发者还是可以很容易地察觉到问题。而 frommoduleimport*这种方式会让开发者导入 module中的所有公有类,函数,变量,从而使当前脚本中被导入了很多未知的变量名,让代码的管理变得更加复杂和不可控。不过,我们还是有办法控制 frommoduleimport*的行为的——用 __all__属性。如果在 module脚本中定义了 __all__属性,那么 frommoduleimport*就只会导入 __all__中的变量名:

# module.py
__all__ = ["fun"] # from module import * 只会导入fun
def fun():return True
def fun1(): # from module import * 不会导入fun1pass
var1 = False # from module import * 不会导入var1

sys.argv[0]和_file_

sys.argv[0]用来获取入口执行文件的路径。__file__用来获取当前脚本文件的路径。为了加深理解,做个小试验:

假设我的目录:

|-Users

|--myname

|----test1.py

|----test2.py

test1.py:

import sys
print(__file__)
print(sys.argv[0])

test2.py:

import test1

执行test1.py:

python test1.py

得到结果:

test1.py test1.py

执行test2.py:

python test2.py

得到结果:

/Users/myname/test1.py test2.py

在上一级目录执行test1.py:

python myname/test1.py

得到结果:

myname/test1.py myname/test1.py

在上一级目录执行test2.py:

python myname/test2.py

得到结果:

/Users/myname/test2.py myname/test2.py

05令人困扰的自引用问题

上面介绍了很多关于Python内部的路径管理的规则和原理。其实介绍这些规则和原理的终极目标就是解决令人困扰的自引用问题。在你写一个项目时,假设你的文件结构如下:

|-myproject

|----tools

|--------_init_.py

|--------trainer.py

|----utils

|--------_init_.py

|--------trans.py

|----test.py

如果在 test.py中需要用到 tools/trainer.py中的函数,那么在 test.py中直接引用即可:

import tools.trainer

这种方式其实是用了前面我们聊到的当前路径索引,解释器从当前目录出发,查找相对路径为 tools/trainer的模块。这时候我们可以完美运行 test.py

注意:文件夹下必须有_init_.py文件,解释器才能够找到模块。

但是如果在 utils/trans.py中需要用到 tools/trainer中的函数:

import tools.trainer

就会收到 ModuleNotFoundError的错误信息。因为解释器查找当前脚本路径时,找不到 tools/trainer.py这个文件,正确的路径应该是 ../tools/trainer.py,因为当前的执行脚本是 utils/trans.py。那么我们修改一下路径:

import sys
sys.path.insert(0, "../")
import tools.trainer

sys.path.insert(0,"../")会把上级目录 ../插入 sys.path列表的首位,这也就是前文说的,通过sys模块来修改默认的索引路径。这样会强制解释器搜索当前脚本路径的上级路径,解释器就可以找到我们需要的模块。

上文所述的方法是一种比较方便但是并不是很规范的方式,因为如果按照PEP-8的规范, import语句要在代码最前面, sys.path.insert(0,"../")这条语句插在两个 import语句中间,其实是违反了PEP-8规范。所以,更加规范的方式是什么呢?

笔者自己也很困惑这个问题,于是参考了一些开源的Python项目,发现他们一般用 site_packages路径索引而非用当前脚本路径索引,由于 site_packages路径索引会直接把 myproject路径加入索引列表,所以 tools/trainer.py可以在系统的任何路径下被索引到,问题自然得到解决。那么如何让Python解释器知道某条 import语句用哪种索引方法呢?回顾一下 路径索引顺序这一节,我们提到解释器会在sys.path这个路径列表搜索模块,默认情况下,会先从当前路径开始搜索,然后搜索环境变量,最后搜索site-packages路径。所以要让解释器用 site_packages路径索引,我们需要确保:

  • 当前路径下没有与所导入模块重名的文件
  • 所导入的模块(文件)在 site_packages路径下

第一个条件很容易达成,第二个条件一般有两种办法实现。如果当前项目myproject是一个纯Python项目,可以直接把myproject文件夹复制到 site_packages目录下,虽然可以使用,不过这种方式非常不规范。更规范的方式是用 setup.py把项目安装在本地,关于 setup.py的使用我会在后面的专题中详细介绍。

到此,我们就解决了这个令人困扰的自引用问题。

结语

本专题从Python路径管理的原理出发,介绍了模块导入的路径索引顺序、from和import导入的区别、sys.argv[0]和_file_的含义。最后为大家提供了令人困扰的自引用问题的两种解决办法。其实对于笔者来说,在项目中导入自己的模块产生的路径问题困扰了我很久,直到看了一些开源的项目以及跟大佬们交流学习才知道如何处理这类问题。希望读者朋友们看完这篇专题后可以有所收获,如果你对本文有任何疑问或者建议,欢迎留言交流!

6900f6683f8eb1a725f66c829c0d0453.png
【Python专题(二)】Python二三事​mp.weixin.qq.com
e5070b2680f66ec3f81219ceeb3fa6e4.png
【Python专题(一)】python环境搭建​mp.weixin.qq.com
e5070b2680f66ec3f81219ceeb3fa6e4.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/486709.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前沿研究:21世纪工程领域的重大挑战 | 中国工程院院刊

本文选自中国工程院院刊《Engineering》2020年第7期作者:C.D. Mote Jr.来源:Engineering in the 21st Century: The Grand Challenges and the Grand Challenges Scholars Program[J].Engineering,2020,6(7):728-732.编者按近期,中国工程院外…

linux网站目录在哪_果核建站教程【二】环境安装与搭建第一个网站

有问题加群,一起讨论,一起学习群号:664592923昨天大家都能理解,那么今天我们就要进入实战教程咯。这节教程讲在本地搭建环境和安装程序。1本地环境的搭建之前有教程讲如何在Windows开启Linux系统,本来想直接让大家在Li…

北斗定位2.0版来了!普通人手机可用,全免费!

◎ 科技日报记者 张佳星1.0版解决快的问题,2.0版解决又快又准的问题,是1.0基础上的一个巨大升级!10月14日,在北斗卫星导航系统高峰论坛上,中国信息通信研究院(下简称“信通院”)发布了北斗高精度…

做出明智的决策

无处不在的决策 在我们的一生中,会做出无数的决定或决策,有关于个人生活的,也有工作专业相关的,这发生在我们的每一天中。在这些决策中,有一些无关紧要,有一些却会产生长期影响,乃至导致颠覆性的…

如何看打印机的缓存区域_松下打印机好吗 松下打印机卡纸如何解决【详解】...

现在人们早已习惯了用手机记录下生活中的美好事物,因此拥有一台能打印照片的打印机成为这些人的选择,可随着现在人们对于打印机的需求量在不断的增加,市面上的打印机品牌也随之增多了起来。那么松下 打印机怎么样,松下打印机使用过…

Linux 蓝牙读写,实战Linux Bluetooth编程(三) HCI层编程

作者:Sam (甄峰)(HCI协议简介,HCI 在BlueZ中的实现以及HCI编程接口)1. HCI层协议概述:HCI提供一套统一的方法来访问Bluetooth底层。如图所示:从图上可以看出,Host Controller Interface(HCI) 就是用来沟通Host和Modul…

碰疼了会躲!这个植入“迷你大脑”的AI机器人,可感知疼痛,还能自我愈合...

来源:雷锋网人类为什么会产生痛觉?没错,是因为大脑中枢神经。和触觉、温度等感觉一样,我们对疼痛非常敏感,当受到外界“轻微”刺激时,体内的神经元产生相应的信号,并传输至大脑中的中枢神经系统…

哈佛大学惊人发现:新冠对人类未来影响巨大!

来源:北美观察家近日,哈佛大学公共卫生学院发了一篇Science:根据论文中的描述,无论是否能研发出疫苗,新冠病毒都可能会陪伴人类到2025年。那么,2025年以后人类能摆脱新冠病毒吗?不,只…

服务的分类与启动

一、服务的分类 查询已安装的服务 RPM包安装的服务 [rootbogon ~]# chkconfig --list# 查看服务自启动状态,可以看到所有RPM包安装的服务 # 此命令不可以查看源码包安装的服务 注:1、2、3、4、5、6是运行级别 源码包安装的服务 查看服务安装位置&#xf…

在Linux里awk与sed的区别,linux awk和sed讲解

sed 工具简介在了解了一些正规表示法的基础应用之后,再来呢?呵呵~两个东西可以玩一玩的,那就是 sed 跟 awk 了!这两个家伙可是相当的有用的啊!举例来说,鸟哥写的 logfile.sh 分析登录文件的小程…

python编辑器_推荐一款Python编辑器,集Pycharm和Sublime优点于一身的王者

编程里面的编辑器就像是武林大会里面的高手,每一年都有新秀,黑马出现!比如有练习霸道的天罡之气的榜首Pycharm,力量雄厚霸道战斗力极强,但是对斗气消耗很大,占内存大而且启动速度有点慢!还有练习…

因果解释能够对规则进行解释吗?

来源:《哲学动态》2017年第10期作者:初维峰(西安交通大学人文社会科学学院)本文受中国博士后科学基金面上资助项目“当代西方因果解释理论研究”(2017M613160)资助。在现实生活中,我们不仅要对某一事件进行解释&#x…

okhttp post json 数据_使用python抓取App数据

App中的数据可以用网络爬虫抓取么答案是完全肯定的:凡是可以看到的APP数据都可以抓取。下面我就介绍下自己的学习经验和一些方法吧 本篇适合有过web爬虫基础的程序猿看没有的的话学的可能会吃力一些App接口爬取数据过程使用抓包工具手机使用代理,app所有…

JS的typeof力所能及已经力所不及

typeof返回值列表 typeof的作用 返回参数的类型 typeof能判断的类型 String类型: typeof a stringUndefined类型: typeof undefined undefinedBoolean类型: typeof true booleanNumber类型: typeof 22 numberSymbol类型: typeof Symbol() symbolFunction类型:typeof funct…

忆阻器类脑芯片与人工智能

来源:文章转载自期刊《微纳电子与智能制造》作者:陈子龙,程传同,董毅博,张 欢,张恒杰,毛旭瑞,黄北举,谢谢。摘 要现阶段计算与存储分离的“冯诺依曼”体系在功耗和速率方…

linux系统下替换图片,Linux(ubuntu系统)下使用FreeImage库

Linux(ubuntu系统)下使用FreeImage库Linux(ubuntu系统)下使用FreeImage库最近在搞一个图像处理的项目,需要用到FreeImage,之前在Windows下用过,很简单,因为FreeImage官网提供了可供使用的静态库动态库,直接包含就行了。…

UWP Composition API - PullToRefresh

UWP Composition API - PullToRefresh 原文:UWP Composition API - PullToRefresh背景: 之前用ScrollViewer 来做过 PullToRefresh的控件,在项目一些特殊的条件下总有一些问题,比如ScrollViewer不会及时到达指定位置。于是便有了使用Composit…

从城市治理到城市“智”理,AI 不仅是城市管理的“眼睛”

来源:帮尼资讯部分参考来源:中国安防行业网,图片来源网络近年来,随着计算机视觉技术的长足进步,AI在城市管理领域广泛部署。其中,AI视频分析识别技术成为城市场景中规模最大、数量最多、落地最广泛的应用。…

python3 应用 nose_parameterized 实现unittest 参数化

一、读取变量的值,实现unittest 参数化 import nose_parameterized,unittestdef calc(a:int,b:int):return ab case_data [[10,20,30],[12,21,33],[15,21,36] ] class MyClass(unittest.TestCase):nose_parameterized.parameterized.expand(case_data)def test_comp…

vue data数据修改_VUE的数据响应式

什么是数据响应式?const vm newVUE({data:{n:0}})上面的代码中,如果修改vm.n,那么UI中的n就会通过变化来响应我,这就是数据响应式。VUE对data做了什么?当给一个vue实例传入data的时候,vue内部会对传入的dat…