草庐IT

import原理

lxd670 2023-03-28 原文

1.模块(Module)和包(Package)

1.1 理解模块(Module)

理解为是一个py文件

  • module是组织单位,它自己独立构成一个命名空间,它本身是一个Python object
  • 在Python object里面,还可以有很多其他的Python object
  • 实际应用中, module对应的是py文件。

1.2 理解包(Package)

理解为一个文件夹

  • package是一种特殊的module
  • package 几乎和 module 有一样的功能,它只是多了一个path
  • 区分packagemodule,是因为在操作系统层级,package往往对应的是一个文件夹(可以有其他的文件夹或者有文件)
  • package里面儿可以有其它的包(subpackage),也可以有模块(module)

2. import都做了哪些事情

  • 1.查找模块文件(通过sys.path可以查看目录的导入顺序)
    • 程序主目录
    • PYTHONPATH 目录
    • 标准链接库目录
  • 2.编译成位码(即pyc文件)
  • 3、执行模块的代码来创建其所定义的变量
    • 导入时,代码是会执行的

3.导入模块(Module)

3-1 查看sys.path目录

如果自定义包没在目录里,可以往目录中添加搜索路径sys.path.append(path)

搜索是从上往下查找,如果中间查到某个包就不会往下查询,尽量把自定义包插入到前面sys.path.insert(0,path)

test_import # 顶层目录
└── a.py
##### a.py
import sys

if __name__ == '__main__':
  print(sys.path)
[
  '/Users/test_import',	# 当前执行py文件所在的文件夹
  '/local/Python3/3.8/lib/python38.zip',
  '/local/Python3/3.8/lib/python3.8',
  '/local/Python3/3.8/lib/python3.8/lib-dynload',
  '/local/Python3/3.8/lib/python3.8/site-packages'	# pip install的位置
]

3-2 导入时代码执行

导入模块/包时,会运行代码把它加载到sys.modules缓存起来。

目录

test_import # 顶层目录
├── a.py
└── b.py

python文件

##### b.py
print('我是b.py')

##### a.py
import b
import sys

if __name__ == '__main__':
  print(f"1.我是sys.modules: {dict(sys.modules.items())}")
  print(f"2.打印模块: {b}")
  print('3.我是a.py')

运行结果

➜  python3 a.py 
我是b.py
1.我是sys.modules: {...,'b': <module 'b' from '/Users/test_import/b.py'>}
2.打印模块: <module 'b' from '/Users/test_import/b.py'>
3.我是a.py

3-3 导入模块的object(from M import obj/func/var)

目录

test_import # 顶层目录
├── a.py
└── b.py

python文件

##### b.py
class B:
 @staticmethod
 def get_b():
   print('我是b.py')

##### a.py
from b import B
import sys

if __name__ == '__main__':
  print(f"1.我是sys.modules: {dict(sys.modules.items())}")
  print(f"2.打印类: {B}")
  print('3.我是a.py')

运行结果

➜  python3 a.py 
我是b.py
1.我是sys.modules: {...,'b': <module 'b' from '/Users/test_import/b.py'>}
2.打印类: <class 'b.B'>
3.我是a.py

4.引入包(Package)

在import一个Package会查看Package下面有没有__init__.py文件,没有的话不会运行额外的代码,有的话运行__init__.py

运行__init__.py文件,实际上是开辟了单独的命名空间存放文件内容,然后用这个命名空间来构成一个module(特殊的module)

4-1 查看包信息(import P)

4-1-1 无__init__.py

<module 'mypackage' (namespace)>,只有namespace

目录

test_import # 顶层目录
├── a.py
└── mypackage
    └── mymodule.py

python文件

##### a.py
import mypackage

if __name__ == '__main__':
  print(mypackage)
  print('我是a.py')

运行结果

➜  python3 a.py
<module 'mypackage' (namespace)>
我是a.py

4-1-2 有__init__.py

<module 'mypackage' from '/Users/test_import/mypackage/__init__.py'>,指向具体的__init__.py文件

目录

test_import # 顶层目录
├── a.py
└── mypackage
    ├── __init__.py
    └── mymodule.py

python文件

##### mypackage/__init__.py
print('我是mypackage的__init__.py')

##### a.py
import mypackage

if __name__ == '__main__':
  print(mypackage)
  print('我是a.py')

运行结果

➜  python3 a.py
我是mypackage的__init__.py
<module 'mypackage' from '/Users/test_import/mypackage/__init__.py'>
我是a.py

4-2 查看包有没有引入模块(import P)

import package时,查看包下面的模块有没有被导入

4-2-1 无__init__.py

dir(mypackage)中没有mymodule的命名空间

目录

test_import # 顶层目录
├── a.py
└── mypackage
    └── mymodule.py

python文件

##### a.py
import mypackage

if __name__ == '__main__':
  print(mypackage)
  print(dir(mypackage))
  print('我是a.py')

运行结果

<module 'mypackage' (namespace)>
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
我是a.py

4-2-2 有__init__.py

dir(mypackage)mymodule的命名空间

目录

test_import # 顶层目录
├── a.py
└── mypackage
    ├── __init__.py
    └── mymodule.py

python文件

##### mypackage/__init__.py
class B:
  pass

##### a.py
import mypackage

if __name__ == '__main__':
  print(mypackage)
  print(dir(mypackage))
  print('我是a.py')

运行结果

➜  python3 a.py
<module 'mypackage' from '/Users/test_import/mypackage/__init__.py'>
['B', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
我是a.py

4-3 从包中导入模块(import P from M)

4-3-1 无__init__.py

想查看mypackage信息就查看不了了

目录

test_import # 顶层目录
├── a.py
└── mypackage
    └── mymodule.py

python文件

##### mymodule.py
class Mym:
  ...
  
##### a.py
from mypackage import mymodule

if __name__ == '__main__':
  # print(mypackage)
  # print(dir(mypackage))
  print(mymodule)
  print(dir(mymodule))
  print('我是a.py')

运行结果

➜  python3 a.py
<module 'mypackage.mymodule' from '/Users/test_import/mypackage/mymodule.py'>
['Mym', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
我是a.py

4-3-2 有__init__.py(无内容)

目录

test_import # 顶层目录
├── a.py
└── mypackage
    ├── __init__.py
    └── mymodule.py

python文件

##### mymodule.py
class Mym:
  ...
  
##### a.py
from mypackage import mymodule

if __name__ == '__main__':
  # print(mypackage)
  # print(dir(mypackage))
  print(mymodule)
  print(dir(mymodule))
  print('我是a.py')

运行结果

➜  python3 a.py
<module 'mypackage.mymodule' from '/Users/test_import/mypackage/mymodule.py'>
['Mym', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
我是a.py

4-3-3 有__init__.py(有内容)

目录

test_import # 顶层目录
├── a.py
└── mypackage
    ├── __init__.py
    └── mymodule.py

python文件

##### mymodule.py
class Mym:
  ...
  
##### __init__.py
mymodule = '我是__init__里的mymodule'

##### a.py
from mypackage import mymodule

if __name__ == '__main__':
  # print(mypackage)
  # print(dir(mypackage))
  print(mymodule)
  print(dir(mymodule))
  print('我是a.py')

运行结果

➜  python3 a.py             
我是__init__里的mymodule
[..., 'center', 'count', 'encode', 'endswith', ...]
我是a.py

4-4 直接导入(import P.M)

import mypackage.mymodule时,单独使用mymodule会报错NameError: name 'mymodule' is not defined

必须mypackage.mymodule一起使用

4-4-3 无__init__.py

目录

test_import # 顶层目录
├── a.py
└── mypackage
    └── mymodule.py

python文件

##### mymodule.py
class Mym:
  ...

##### a.py
import mypackage.mymodule

if __name__ == '__main__':
  print(mypackage)
  print(dir(mypackage))
  # print(mymodule)	# 报错
  # print(dir(mymodule))	# 报错
  print(mypackage.mymodule)
  print(dir(mypackage.mymodule))
  print('我是a.py')

运行结果

➜  python3 a.py
<module 'mypackage' (namespace)>
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'mymodule']
<module 'mypackage.mymodule' from '/Users/test_import/mypackage/mymodule.py'>
['Mym', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
我是a.py

4-4-3 有__init__.py(无内容)

效果和没有__init__.py执行是一样的

目录

test_import # 顶层目录
├── a.py
└── mypackage
    ├── __init__.py
    └── mymodule.py

python文件

##### mymodule.py
class Mym:
  ...

##### a.py
import mypackage.mymodule

if __name__ == '__main__':
  print(mypackage)
  print(dir(mypackage))
  # print(mymodule)	# 报错
  # print(dir(mymodule))	# 报错
  print(mypackage.mymodule)
  print(dir(mypackage.mymodule))
  print('我是a.py')

运行结果

➜  python3 a.py
<module 'mypackage' from '/Users/test_import/mypackage/__init__.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'mymodule']
<module 'mypackage.mymodule' from '/Users/test_import/mypackage/mymodule.py'>
['Mym', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
我是a.py

4-4-3 有__init__.py(有内容)

目录

test_import # 顶层目录
├── a.py
└── mypackage
    ├── __init__.py
    └── mymodule.py

python文件

##### mymodule.py
class Mym:
  ...
  
##### __init__.py
mymodule = '我是__init__里的mymodule'

##### a.py
import mypackage.mymodule

if __name__ == '__main__':
  print(mypackage)
  print(dir(mypackage))
  # print(mymodule)
  # print(dir(mymodule))
  print(mypackage.mymodule)
  print(dir(mypackage.mymodule))
  print('我是a.py')

运行结果

➜  python3 a.py
<module 'mypackage' from '/Users/test_import/mypackage/__init__.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'mymodule']
<module 'mypackage.mymodule' from '/Users/test_import/mypackage/mymodule.py'>
['Mym', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
我是a.py

5.关于__init__.py

在python3中,文件夹下无论有没有__init__.py文件,这个文件夹都可以作为一个包(Package)被python使用

可以存放和普通模块一样的代码(量、类、函数..)

__init__.py中使用相对导入

5-1 简化import语法

5-1-1 无__init__.py

需要指名道姓的支出使用哪个obj/func/var

目录

test_import # 顶层目录
├── a.py
└── mypackage
    └── mymodule.py

python文件

##### mypackage/mymodule.py
class Mym:
  @staticmethod
  def get_mym():
    print('我是Mym的')

##### a.py
from mypackage.mymodule import Mym

if __name__ == '__main__':
  Mym().get_mym()

运行结果

➜  python3 a.py
我是Mym的

5-1-2 有__init__.py

from p.x.x.x.m import obj转变为from p import obj的效果

目录

test_import # 顶层目录
├── a.py
└── mypackage
    ├── __init__.py
    └── mymodule.py

python文件

##### mypackage/mymodule.py
class Mym:
  @staticmethod
  def get_mym():
    print('我是Mym的')

##### mypackage/__init__.py
from .mymodule import Mym

##### a.py
from mypackage import Mym

if __name__ == '__main__':
  Mym().get_mym()

运行结果

➜  python3 a.py
我是Mym的

5-2 批量导入和规范化导入以及__all__

用于管理导出的方法,只在from p import *是生效

有效: __init__.py使用from m import * 同时a.py使用from p import *时才生效

无效: __init__.py使用from m import *a.py使用from p import fun3那么会绕开__all__设置的规则, 可以直接使用fun3

目录

test_import # 顶层目录
├── a.py
└── mypackage
    ├── __init__.py
    └── mymodule.py

python文件

##### mypackage/mymodule.py 
def fun1():
  print('我是fun1')

def fun2():
  print('我是fun2')

def fun3():
  print('我是fun3')


##### mypackage/__init__.py 
from .mymodule import *

__all__ = ['fun1', 'fun2']


##### a.py
from mypackage import *

if __name__ == '__main__':
  fun1()
  fun2()
  # fun3() 报错NameError: name 'fun3' is not defined

运行结果

➜  python3 a.py
我是fun1
我是fun2

6.绝对导入和相对导入

6-1 绝对导入

目录

test_import # 顶层目录
├── a.py	# 引用了b.py和c.py[子孙关系]
├── p1
│   ├── b.py     # 引用了c.py[长辈关系]
│   └── p11
│       └── c.py # 有一个def run():print('我是c.py')
└── p2
    ├── p21
    │   └── d.py # 引用了e.py[堂兄弟关系]
    └── p22
        └── e.py # 有一个def run():print('我是e.py')

文件内容

##### p1/b.py 
from p1.p11 import c
c.run()

##### p2/p21/d.py 
from p2.p22 import e
e.run()

##### a.py
from p1 import b
from p2.p21 import d

6-1-1 绝对-运行主文件(a.py)

➜  python3 a.py
我是c.py
我是e.py

6-1-2 绝对-运行子包下面的模块(b.py)

# 在test_import文件夹内调用b.py
➜  python3 p1/b.py 
Traceback (most recent call last):
  File "p1/b.py", line 1, in <module>
    from p1.p11 import c
ModuleNotFoundError: No module named 'p1'

# 进入p1文件夹内运行也报错
➜  python3 b.py 
Traceback (most recent call last):
  File "b.py", line 1, in <module>
    from p1.p11 import c
ModuleNotFoundError: No module named 'p1'

# 使用python3 -m运行(b.py顶层外面执行,p1是共同的顶层)
➜  python3 -m p1.b
我是c.py

6-1-3 绝对-运行子包下面的模块(d.py)

# 在test_import文件夹内调用d.py
➜  python3 ./p2/p21/d.py
Traceback (most recent call last):
  File "./p2/p21/d.py", line 1, in <module>
    from p2.p22 import e
ModuleNotFoundError: No module named 'p2'

# 进入p2/p21文件夹运行也报错
➜  python3 python3 d.py 
Traceback (most recent call last):
  File "d.py", line 1, in <module>
    from p2.p22 import e
ModuleNotFoundError: No module named 'p2'

# 使用python3 -m运行(因为是堂兄弟,所以要推到共同顶层外面执行,p2是共同的顶层)
➜  python3 -m p2.p21.d
我是e.py

6-2 相对导入

目录结构和关系都没有变,只在b.pyc.py绝对引入改为相对引入

注意: 入口文件(a.py)不能使用相对引入其他模块,必须为绝对引入

目录

test_import # 顶层目录
├── a.py	# 引用了b.py和c.py[子孙关系]
├── p1
│   ├── b.py     # 引用了c.py[长辈关系]
│   └── p11
│       └── c.py # 有一个def run():print('我是c.py')
└── p2
    ├── p21
    │   └── d.py # 引用了e.py[堂兄弟关系]
    └── p22
        └── e.py # 有一个def run():print('我是e.py')

文件内容

##### p1/b.py(改为相对导入)
from .p11 import c
c.run()

##### p2/p21/d.py(改为相对导入)
from ..p22 import e
e.run()

##### a.py(主文件不能使用相对导入)
from p1 import b
from p2.p21 import d

6-2-1 相对-运行主文件(a.py)

➜  python3 a.py
我是c.py
我是e.py

6-2-2 相对-运行子包下面的模块(b.py)

# 在test_import文件夹内调用b.py
➜  python3 p1/b.py 
Traceback (most recent call last):
  File "p1/b.py", line 1, in <module>
    from .p11 import c
ModuleNotFoundError: No module named '__main__.p11'; '__main__' is not a package

# 进入p1文件夹内运行也报错
➜  python3 b.py 
Traceback (most recent call last):
  File "b.py", line 1, in <module>
    from .p11 import c
ModuleNotFoundError: No module named '__main__.p11'; '__main__' is not a package

# 使用python3 -m运行(b.py顶层外面执行,p1是共同的顶层)
➜  python3 -m p1.b
我是c.py

6-2-3 相对-运行子包下面的模块(d.py)

# 在test_import文件夹内调用d.py
➜  python3 ./p2/p21/d.py 
Traceback (most recent call last):
  File "./p2/p21/d.py", line 1, in <module>
    from ..p22 import e
ValueError: attempted relative import beyond top-level package

# 进入p2/p21文件夹运行也报错
➜  python3 d.py  
Traceback (most recent call last):
  File "d.py", line 1, in <module>
    from ..p22 import e
ValueError: attempted relative import beyond top-level package

➜  python3 -m p2.p21.d
我是e.py

7.初步了解python3 -m

modmodule的缩写,即-m后面跟的是模块(module)名,意思是把模块当成脚本来运行。

python3 -m package_name.py_file_name,结尾不需要加.py

1.运行http.server

会把当前文件夹内的文件显示在页面上

➜  python3 -m http.server 8080
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...
127.0.0.1 - - [22/Mar/2023 23:56:18] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [22/Mar/2023 23:56:20] "GET /p1/ HTTP/1.1" 200 -
127.0.0.1 - - [22/Mar/2023 23:56:22] "GET /p1/p11/ HTTP/1.1" 200 -
127.0.0.1 - - [22/Mar/2023 23:56:28] "GET /p2/ HTTP/1.1" 200 -

有关import原理的更多相关文章

  1. css - rails 萨斯 : variables are not passed with @import - 2

    我有一个使用twitterbootstrap和sass的Rails元素。scss文件结构化到文件夹中,所以我有更好的概述。现在我想为包含我的颜色等的全局变量定义一个文件,并将这些值传递给其他文件,这样我就有更少的冗余代码。虽然所有代码都已正确导入和应用,变量不起作用。这是当前的设置:样式表/application.css.scss/**=require_self*=require_tree*//*stylesheets/||–base/||–_reset.scss#Reset/normalize||–_typography.scss#Typographyrules||–componen

  2. ruby-on-rails - 如何将 "import"嵌套类放入 Ruby 中的当前类? - 2

    在Ruby中,我可以将模块/类嵌套到其他模块/类中。我想要的是在文件或类中添加一些声明,以便能够通过短名称引用嵌套类,例如使用Inner获取Outer::Inner,就像在Java、C#等中一样。语法可能是这样的:moduleOuterclassInner;endclassAnotherInner;endendclassCimportOuter:[:Inner,:AnotherInner]deffInnerendend简单的实现可能是这样的:classClassdefimport(constants)@imported_constants=(@imported_constants||{

  3. 【Unity游戏破解】外挂原理分析 - 2

    文章目录认识unity打包目录结构游戏逆向流程Unity游戏攻击面可被攻击原因mono的打包建议方案锁血飞天无限金币攻击力翻倍以上统称内存挂透视自瞄压枪瞬移内购破解Unity游戏防御开发时注意数据安全接入第三方反作弊系统外挂检测思路狠人自爆实战查看目录结构用il2cppdumper例子2-森林whoishe后记认识unity打包目录结构dll一般很大,因为里面是所有的游戏功能编译成的二进制码游戏逆向流程开发人员代码被编译打包到GameAssembly.dll中使用il2ppDumper工具,并借助游戏名_Data\il2cpp_data\Metadata\global-metadata.dat

  4. Slowloris DoS攻击的原理与简单实现 - 2

    前言    Slowloris攻击是我在李华峰老师的书——《MetasploitWeb 渗透测试实战》里面看的,感觉既简单又使用,现在这种攻击是很容易被防护的啦。不过我也不敢真刀实战的去试,只是拿个靶机玩玩罢了。         废话还是写在结语里面吧。(划掉)结语可以不看(划掉)Slowloris攻击的原理        Slowloris是一种资源消耗类DoS攻击,它利用部分HTTP请求进行操作。也叫做慢速攻击,这里的慢速并不是说发动攻击慢,而是访问一条链接的速度慢。Slowloris攻击的功能是打开与目标Web服务器的连接,然后尽可能长时间的保持这些连接打开。如果由多台电脑同时发起Slo

  5. [蓝桥杯单片机]学习笔记——串口通信的基本原理与应用 - 2

    目录一、原理部分1、什么是串行通信(1)并行通信与串行通信(2)串行通信的制式(3)串行通信的主要方式  2、配置串口(1)SCON和PCON:串行口1的控制寄存器(2)SBUF:串行口数据缓冲寄存器 (3)AUXR:辅助寄存器​编辑(4)ES、PS:与串行口1中断相关的寄存器(5)波特率设置  3、串口框架编写二、程序案例一、原理部分1、什么是串行通信(1)并行通信与串行通信微控制器与外部设备的数据通信,根据连线结构和传送方式的不同,可以分为两种:并行通信和串行通信。并行通信:数据的各位同时发送与接收,每个数据位使用一条导线,这种方式传输快,但是需要多条导线进行信号传输。串行通信:数据一位一

  6. ruby - # Ruby 中识别方法约定的基本原理/历史是什么? - 2

    例如,我一直看到称为String#split的方法,但从未见过String.split,这似乎更合乎逻辑。或者甚至可能是String::split,因为您可以认为#split位于String的命名空间中。当假定/隐含类(#split)时,我什至单独看到了该方法。我知道这是ri中识别方法的方式。哪个先出现?例如,这是为了区分方法和字段吗?我还听说这有助于区分实例方法和类方法。但这从哪里开始呢? 最佳答案 不同之处在于您如何访问这些方法。类方法使用::分隔符来表示消息可以发送到类/模块对象,而实例方法使用#分隔符表示消息可以发送到实例对

  7. H264压缩原理 - 2

    1、为什么压缩的原始数据一般采用YUV格式(1)利用人对图片感觉的生理特性,对于亮度信息比较敏感,对于色度信息不太敏感,所以视频编码是将Y分量和UV分量分开来编码,并且可以减少UV分量.2、视频压缩原理(1)空间冗余:图像相邻像素之间的相关性,比如一帧图片被划分成多个16x16的块之后,相邻的块之间有很多明显的相似性。(2)时间冗余:时间相差较近的两张图片变化较小。(3)视觉冗余:我们的眼睛对某些细节不太敏感,对图像中的高频信息的敏感度小于低频信息,可以去除一些高频信息。(4)编码冗余:一幅图片中不同像素出现的概率是不同的,对于出现次数较多的像素,用少的位数来编码,对于出现次数较少的像素,用多

  8. Python——程序的运行原理 - 2

    Python程序运行原理Python是一种脚本语言,编辑完成的程序,也称源代码,可以直接运行。从计算机的角度看,Python程序的运行过程包含两个步骤:解释器将源代码翻译成字节码(即中间码),然后由虚拟机解释执行。Python程序文件的扩展名通常为.py。在执行时,首先由Python解释器将.py文件中的源代码翻译成中间码,这个中间码是一个扩展名为.pyc的文件,再由Python虚拟机(PythonVirtualMachine,PVM)逐条将中间码翻译成机器指令执行。需要说明的是,pyc文件保存在Python安装目录的pycache文件夹下,如果Python无法在用户的计算机上写人字节码,字节

  9. mysql - Rails 数据库连接池的工作原理 - 2

    我正在学习Rails数据库连接池概念。在Rails应用程序中,我将池大小定义为5。我对连接池大小的理解如下。当服务器启动时,rails会自动创建n个在database.yml文件中定义的连接。在我的例子中,它将创建5个连接,因为池大小为5。在每个http请求上,如果需要访问数据库,rails将使用连接池中的可用连接来处理请求。但我的问题是,如果我一次达到1000个请求,那么大部分请求将无法访问数据库连接,因为我的连接池大小只有5个。我上面对rails连接池的理解对吗??谢谢, 最佳答案 目的:数据库连接不是线程安全的;所以Activ

  10. ruby - sass @import "compass/reset"错误 - 2

    我想在我的静态HTML项目中使用带有Compass的Sass,但按照说明操作是行不通的。这就是我所做的:$geminstallcompass$cd$compassinstallcompass.正在等待:directory./sass/directory./stylesheets/create./sass/screen.scsscreate./sass/print.scsscreate./sass/ie.scsscreate./stylesheets/screen.csscreate./stylesheets/ie.csscreate./stylesheets/print.css但是当我

随机推荐