网络编程
位置:首页>> 网络编程>> Python编程>> 可能是史上最细的python中import详解

可能是史上最细的python中import详解

作者:天天开心学编程  发布时间:2023-01-07 18:40:07 

标签:python,import,机制

以前在使用import的时候经常会因为模块的导入而出现一些问题,以及一些似懂非懂半疑惑半糊涂的问题,索性花了点时间研究了一些python引用的方法,并且动手操作试验了一下,深有感触,特留此文以作总结,如有不当之处欢迎评论指正

本文会尽我所能详细描述,字数会比较多,希望各位耐心看完。

首先我觉得应该先了解一下python的引用是怎么引用的

我们首先新建一个python文件demo.py

print(dir())

dir()命令是获取到一个object的所有属性,当传值为空时默认传入的是当前py文件,我们可以通过这个函数来查看py文件的所有属性

['__annotations__', '__builtins__', '__cached__', '__doc__',
'__file__', '__loader__', '__name__', '__package__', '__spec__']

双下划线开头结尾的变量是python中一类特殊的变量,称为python的魔法函数,这里简单解释一些常见属性的意义

  • __annotations__:预定义的变量类型

  • __doc__:文档注释,仅包括第一个''' '''内部的注释文档

  • __file__:文件名,根据被引用还是被执行返回绝对路径还是相对路径

  • __name_:文件名,被执行文件该属性为__main__,被引用文件则返回包名

当我们在python文件中写入一些代码后

a = 1
class b:
   def __init__(self) -> None:
       self.value = "123"
c = [1,2,3]

def f(a,b):
   return a+b
print(dir())

再次执行后可以发现

['__annotations__', '__builtins__', '__cached__', '__doc__',
 '__file__', '__loader__', '__name__', '__package__', '__spec__', 
'a', 'b', 'c', 'f']

相较于之前,所有的变量、类、函数都被加入py文件的属性值中了,也正是如此才能在之后使用这些已经声明的变量或者函数。

对于以下比较常见的库文件引入方式

import math
import torch.nn as nn
from numpy import arange
print(dir())

同理我们可以比较清晰的看到,当引入了一个python库文件的时候其实也就是在python文件中加入了这个库名字,如果是用 as 关键字进行重命名在文件中也会以重命名之后的名字来做保留

['__annotations__', '__builtins__', '__cached__', '__doc__',
 '__file__', '__loader__', '__name__', '__package__', '__spec__',
 'math','nn','arange']

这时我突然产生了一个疑问,那我们使用的print,dir这两个函数又是在哪里定义的呢,我似乎并没有引用任何的库就直接使用了呢。

这其实是一个相当有趣的问题,不过我们先稍等一下,在后面我会回答这个问题。

我们再来带入一个实际的场景,通常一个较为复杂的项目是多文件协同工作的,其中不乏为了命名空间的统一一致性,为了整体文件结构的清晰有序等多种目的而使用多级目录来合理划分文件关系,梳理整体代码架构。

我们引入如下的文件系统环境(此示意图会在文中适当的位置重复出现以加强记忆)

|—— python
|    |—— demo.py
|    |—— folder1
|        |—— a.py
|        |—— b.py
|    |—— folder2
|        |—— c.py
|        |—— d.py

并且每一个a/b/c/d.py文件中分别定义了f1-f4函数以供调用,示意如下:

#a.py
def f1():
   print("this is function f1 in a.py")

然后我们在demo.py中执行以下代码,很显然正确引入没有问题

#demo.py
from folder1.a import f1
from folder1.b import f2
from folder2.c import f3
from folder2.d import f4

f1()
f2()
f3()
f4()

# 输出:
# this is function f1 in a.py
# this is function f2 in b.py
# this is function f3 in c.py
# this is function f4 in d.py

如果我在a.py中想使用b.py中的f2,我也可以更改并执行,没有任何问题

from b import f2

def f1():
   print("this is function f1 in a.py")

f2()

# 输出:
# this is function f2 in b.py

但如果我想在a.py中使用c.py中的f3显然需要一些别的手段,因为这涉及到了跨文件夹的引用

|—— python
|    |—— demo.py
|    |—— folder1
|        |—— a.py
|        |—— b.py
|    |—— folder2
|        |—— c.py
|        |—— d.py

考虑到文件结构层次,a.py位于目录folder1下,我们希望a.py能够回到上一级目录python下,这样就能再进入folder2/c.py顺利引用了。

很多文件也都是这样做的,加入了一个import sys,sys.path,sys.path.append(".")然后问题似乎就顺利解决了,

import sys
sys.path.append(".")

from folder2.c import f3

def f1():
   print("this is function f1 in a.py")

f3()

# 输出:
# this is function f3 in c.py

不过这种做法为什么可行呢,我们不妨来探究一下这种做法正确执行背后的逻辑

首先我们了解一下sys.path有什么作用,我们在demo.py中执行

import sys
print(sys.path)

这里我使用的python环境是Anaconda3创建的一个python3.7虚拟环境,环境名称为fastreid

['g:\\learner_lu\\code-grammar\\python',
 'C:\\ProgramData\\Anaconda3\\envs\\fastreid\\python37.zip',
 'C:\\ProgramData\\Anaconda3\\envs\\fastreid\\DLLs',
 'C:\\ProgramData\\Anaconda3\\envs\\fastreid\\lib', 
 'C:\\ProgramData\\Anaconda3\\envs\\fastreid', 
 'C:\\Users\\Administrator\\AppData\\Roaming\\Python\\Python37\\site-packages',
 'C:\\ProgramData\\Anaconda3\\envs\\fastreid\\lib\\site-packages']

我们可以观察到sys.path中包含了许多绝对路径,第一个路径似乎是demo.py的所在的文件夹,其他的路径配置过环境变量的的小伙伴想必会觉得很眼熟。

而如果我们选择执行a.py,我们会得到以下结果:

['g:\\learner_lu\\code-grammar\\python\\folder1',
 'C:\\ProgramData\\Anaconda3\\envs\\fastreid\\python37.zip',
 'C:\\ProgramData\\Anaconda3\\envs\\fastreid\\DLLs',
 'C:\\ProgramData\\Anaconda3\\envs\\fastreid\\lib',
 'C:\\ProgramData\\Anaconda3\\envs\\fastreid',
 'C:\\Users\\Administrator\\AppData\\Roaming\\Python\\Python37\\site-packages',
 'C:\\ProgramData\\Anaconda3\\envs\\fastreid\\lib\\site-packages']

唯一的区别就是第一个,也印证了我们的猜想,sys.path中的第一个值是被执行的py文件所在文件夹在操作系统中的绝对路径。

那么现在问题来了,其余的路径是什么呢?

  • C:\\ProgramData\\Anaconda3\\envs\\fastreid\\python37.zip是python的压缩包,解压之后就会被删除,路径无效

  • C:\\ProgramData\\Anaconda3\\envs\\fastreid\\DLLs中是所有的.pyd格式的文件,是一种D语言的加密格式,该格式可以被引用但是不能被查看源代码。

  • C:\\ProgramData\\Anaconda3\\envs\\fastreid\\lib中是python自带的一些库,随python一起安装,可以看到我们常见的一些copy.py,glob.py,io.py,os.py

  • C:\\ProgramData\\Anaconda3\\envs\\fastreid是python解释器python.exe所在的目录 ,也是整个py文件被执行时需要启动用来逐行解释语句的文件

  • 剩下两个site-packages则分别是使用pip install / conda install时包的安装位置, 相信对于使用python的小伙伴们来说下载第三方库的操作并不陌生

来源:https://blog.csdn.net/m0_64355682/article/details/122818873

0
投稿

猜你喜欢

  • 前言我们上一篇博客,给大家展现了一个动态的爱心。今天,我们给大家画一个圣诞树,我们一起来看看效果吧。效果展示我们先来看看最终的效果看看我们画
  • 目录前言:1.Navicat简介2.简易教程分享连接管理库表操作查询窗口筛选表数据运行与转储 SQL 文件导入与导出向导查看页面设置工具目标
  • 很多网站现在都有使用QQ作为在线客服工具,我们点击它可以很方便的和网站人员联系,本站为你整理了在网站上使用QQ在线客服的代码,共13种风格,
  • 1.分包背景这里首先介绍下MultiDex的产生背景。当Android系统安装一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的
  • 在写脚本的过程中,除了发送form表单参数之外,我们还会发送json格式的参数。那么碰见json格式要怎么发送呢,这篇我们来解决这个问题。直
  • 本文实例讲述了python转换字符串为摩尔斯电码的方法。分享给大家供大家参考。具体实现方法如下:chars = ",.012345
  • MySQL的自增id都定义了初始值,然后不断加步长。虽然自然数没有上限,但定义了表示这个数的字节长度,计算机存储就有上限。比如,无符号整型(
  • Go 互斥锁的实现原理?Go sync包提供了两种锁类型:互斥锁sync.Mutex 和 读写互斥锁sync.RWMutex,都属于悲观锁。
  • 在这个周末刚刚写出来的python桌面应用--网络聊天室,主要通过pyqt5作为桌面应用框架,socket作为网络编程的框架,从而实现包括客
  • 本文实例为大家分享了python环境路径设置方法,以及命令行运行python脚本,供大家参考,具体内容如下找Python安装目录,设置环境路
  • 根据"客服果果"的"十几行的超简日历组件"http://bbs.51js.com/viewthrea
  • 前言在前边的几篇文章中已经基本分享完了编译器前端的一些工作,后边的几篇主要是关于编译器对抽象语法树进行分析和重构,然后完成一系列的优化,其中
  • 这篇文章主要介绍了微信小程序 云开发模糊查询实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友
  • 前言对于我这种小白来说,本地环境搭建常规的操作一向是直接去go官网下载go安装包,本机进行安装,然后配置相应的GOROOT和GOPATH,再
  • 目录一、线程基础以及守护进程二、线程锁(互斥锁)三、线程锁(递归锁)四、死锁五、队列六、相关面试题七、判断数据是否安全八、进程池 &
  • 【一:下载·安装】1.下载node.js下载地址:Node.js  或者 点击这里下载2.安装2.1选择No
  • Jquery中的一些东西学习一下子,补充完善一下,毕竟有些时候没有使用到这个方式很有用,在使用bootstrap table的时候,选择当前
  • 本文实例讲述了Python闭包思想与用法。分享给大家供大家参考,具体如下:浅谈 python 的闭包思想首先 python的闭包使用方法是:
  • pip的基本使用安装pip1. cd 到你的python安装目录下的的Scripts文件夹下:2.执行easy_install.exe pi
  • python中向上取整可以用ceil函数,ceil函数是在math模块下的一个函数。向上取整需要用到 math 模块中的 ceil() 方法
手机版 网络编程 asp之家 www.aspxhome.com