为了更好的开发、维护、管理项目,我们需要了解python中项目的组织结构。
1.组织结构
在python中最顶级的是包
(文件夹),包下面有模块
(py文件),模块下面有类
。一个包
可以包含多个模块,一个模块
可以包含多个类。
包
|--模块1
|--类11
|--类12
|--模块2
|--类21
|--类22
####示例
server
|--s1.py
|--s2.py
|--s3.py
2.包与模块命名
python包
一般命名包就是命名一个文件夹名称
,包之间的区分就是通过不同的名称来区分的。包下面也可以有子包
。python
是如何区分文件夹
和包
,在python中,如果定义一个python包
,那么这个python包
下面必须要有__init__.py
文件,如果没有这个文件,python就认为这是一个文件夹而不是一个包。
__init__.py
文件是声明这是一个python包,在__init__.py
文件中可以什么都不写,也可以像其他*.py
文件一样在里面声明变量、函数、类等。
server
|--__init__.py
|--demo #子包
|--d1.py
|--s1.py
|--s2.py
python模块
python模块可以简单的认为是一个后缀为py
的python文件。模块名就是文件的名称。
server
|--__init__.py
|--s1.py
|--s2.py
net
|--__init__.py
|--s1.py
对于上面两个不同包下面相同的模块名称,我们如何区分。在代码中,如果我们引入模块时,有两个相同的模块名称,那么我们需要再模块前面加上包名
# 导入server包下面 s1模块
import server.s1
3.导入模块
improt 模块
在编写代码时,我们有时会需要其他模块的变量或者方法,那么如何导入其他模块的变量、方法呢?
文件结构
./
|-server
|--__init__.py
|--s1.py
|--s2.py
s1.py
如何在s2.py
模块中使用s1.py
模块的变量
s2.py
使用as重新命名
当导入的模块不是当前包中的同级模块时,在导入时需要添加包名包名.模块名
from import 模块
上面import
是导入模块,form improt
可以单独导入模块中的变量或方法,依旧用上面的例子举例
s2.py
- import s1
- print(s1.a)
+ from s1 import a
+ print(a)
from import
不仅可以导入模块中的变量
、方法
,也可以导入模块
#假设在net包下有个n1.py模块
from net import n1
# 从net包下面导入 n1模块
使用*导入模块全部变量
# 导入s1模块下面所有的变量
from s1 import *
一般是不建议导入模块的全部变量,可以在s1
模块中设置
s1.py
__all__ = ['a','b']
a = 1
b = 2
c = 3
在s2.py模块中from s1 import *
中就只会导入a
、b
两个变量
4.__init__的用法
__init__.py
是包的初始化文件,当包被导入时,首先加载执行__init__.py
文件,是自动加载执行的。
批量导入模块
当多个模块中需要使用多个系统模块,如果在每个模块中导入相同的系统模块,就会显得比较繁琐。
server
|--net
|--__init__.py
|--s1.py
|--s2.py
假设在s1
和s2
中需要引入多个相同的模块时,可以在__init__.py
中引入,然后在s1
和s2
模块中分别导入net
包就可以了
__init__.py
import sys
import datetime
import io
s1.py 和 s2.py
5.包与模块几个常见错误
包与模块几个常见的错误:
- 包和模块不会被重复导入
- 避免循环导入包(A->B模块,在B->A模块)
- 当python中一旦导入一个模块时,就会执行这个模块所有代码
- 通常情况下,一个包只有一个入口文件
6.内置变量
除了我们可以在模块中定义变量,模块中也会有系统内置变量。 查看模块里内置变量
a = 1
b = 2
info = dir()
print(info)
"""
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'b']
"""
从上面打印出来的变量我们可以看到系统内置变量都是__
开头和结尾的,最后a
、b
变量是我们在文件中自定义的
变量 | 描述 |
---|
annotations | 注解 |
doc | 模块中的注释 |
file | 模块路径 |
name | 模块名称 |
package | 包的名称 |
7.入口文件和普通模块内置变量
文件结构
server
|--demo
|--__init__.py
|--s1.py
|--s2.py
s1.py
"""
s1模块的注释
"""
print('=======================s1========================')
print('package: ' + (__package__ or '当前模块不属于任何包'))
print('name: ' + __name__)
print('doc: ' + (__doc__ or '当前模块没有注释'))
print('file: ' + __file__)
s2.py
import demo.s1
print('=======================s2========================')
print('package: ' + (__package__ or '当前模块不属于任何包'))
print('name: ' + __name__)
print('doc: ' + (__doc__ or '当前模块没有注释'))
print('file: ' + __file__)
运行s2模块
输出内容
================s1======================
package: demo
name: demo.s1
doc:
s1模块的注释
file: C:\Users\Administrator\Desktop\py\server\demo\s1.py
=================s2==================
package: 当前模块不属于任何包
name: __main__
doc: 当前模块没有注释
file: s2.py
从打印的出的信息中可以看出,当python s2.py
时,其实是把s2设置成python的入口文件,在入口文件中导入s1模块,s1是普通模块,s2是入口文件,可以对比一下输出的信息发现入口文件中package
不属于任何包,且name
不在是模块名称,而变成__mian__
__name__应用
在实际开发中我们可能需要区分入口文件还是普通模块来处理不同的逻辑代码
if __name__ == '__mian__':
pass
8.相对导入和绝对导入
文件结构
demo
|--package1
|--p1.py
|--p2.py
|--package2
|--p3.py
|--mian.py
顶级包和入口文件
python中顶级包
是和入口文件
目录级相同,我们看上面的文件结构,根
目录是demo
,当运行python main.py
,将main.py
作为入口文件,此时顶级包就是package1、package2
,而不是demo
,要想将demo做为顶级包,就需要将mian.py
放在和demo同级
入口文件:
一般就是python
命令运行某个模块,但是也不一定,如果python -m 模块
就是将这个python模块当做普通模块来运行。具体要判断是不是入口文件,还是要打印模块中内置变量 __name__
看其是不是__name == '__main__'
注意:入口文件不允许使用相对路径,必须使用绝对路径
绝对路径
在python模块中,看到
# main.py
import package1.p2
这段代码import路径就是一个绝对路径,绝对路径在导入时,一定要从顶级包开始。
相对路径
python 中相对路径.
表示当前目录,..
表示上一层目录,...
表示上上一层目录,然后依次类推。import
只能写绝对路径,如果需要使用相对路径必须使用from import
# p3.py
#入口文件依然是mian.py
#绝对路径
import p1
#相对路径
from .p1 import m
python中相对路径之所以能够定位到模块是因为内置变量__name__
,入口文件之所以必须使用绝对路径,是因为一旦被python认为是入口文件,那么__name__
发生了改变。不能定位到模块,这就是为什么入口文件必须使用绝对路径