python包-package

概述

在多人开发项目时,不可能 将所有的模块(即 .py文件)放在 同一个 文件夹中

就像安装QQ、office、wps、游戏等软件,文件要放在不同的文件夹里

QQ安装目录:

包

python引入了“包”(package),用于 组织 多个模块(.py文件)

包 在文件系统中就是 文件夹 ,但必须有 __init__.py 文件

在python3.3 开始,没有 __init__.py 文件也可以

命名方式

同变量命名方式相同,小写字母,后面可以有 下划线_ 和 数字

包结构

包名
|----__init__.py
|----模块名.py
注意:
  1. 包文件夹内要有 __init__.py 的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包
  2. __init__.py 可以是 空文件,也可以有 Python代码
  3. 引入包时,会 先执行 __init__.py 文件

例子

工程目录如下:

project
|---main.py
|---user
    |----__init__.py
    |---users.py
    |---reg.py
    |---login.py

users.py,代码如下:

# coding=utf-8

users={}

reg.py

代码如下:

# coding=utf-8
from .users import users

def reg_user(username,password):
    global users
    if username in users.keys():
        print("%s 已经存在,不能注册!"%username)
    else:
        users[username]=password
        print("%s 注册成功!"%username)


if __name__ == "__main__":
    reg_user("luhan","123456")
    reg_user("lixian","000")
    reg_user("luhan","111111")

注意:
由于代码from .users import users,执行该文件报错,但在包外部import正常执行

login.py

代码如下:

# coding=utf-8
from .users import users

def login_user(username,password):
    global users

    pwd=users.get(username)
    if password==pwd:
        print("%s 登录成功!"%username)
    else:
        print("%s 登录失败!"%username)


if __name__ == "__main__":
    login_user("luhan","123456")

注意:
由于代码from .users import users,执行该文件报错,但在包外部import正常执行

__init__.py,代码如下:

#coding=utf-8

print('user.__init__.py')

from . import reg,login

注意:
执行该文件报错,但在包外部import正常执行

main.py

启动文件。
注意:

  1. 在不同包之间import模块,启动文件位置很重要,否则执行时会报错
  2. 只有__init__.py导入了reg,login,才能执行import user就可以调用reg模块的函数
# coding=utf-8

import user

user.reg.reg_user("luhan","123456")
user.reg.reg_user("lixian","111111")
user.reg.reg_user("luhan","888")


# user.login.login_user("luhan","123456")
# user.login.login_user("lixian","888")

while True:
    op=input("请选择操作:\n 1. 登录 \n 2. 注册 \n请输入序号:")
    if op=="1":
        username=input("请输入登录名:")
        password=input("请输入密码:")
        user.login.login_user(username,password)
    elif op=="2":
        username=input("请输入登录名:")
        password=input("请输入密码:")
        user.reg.reg_user(username,password)
    else:
        print("无效操作")

相对导入

相对导入格式

  1. from .A import B,其中. 代表当前模块

  2. from ..X import Y,其中.. 代表上层模块

优点

避免硬编码带来的包维护问题,
例如我们改了某一包的名称,那么其它模块对于其子包的所有绝对导入就不能用了,但是采用相对导入语句的模块,就会避免这个问题

(废弃)例子:

project
|---main.py
|---user
    |----__init__.py
    |---reg.py
    |---login.py
|---goods
    |----__init__.py
    |---view_goods.py
    |---add_goods.py
    |---delete_goods.py
    |---modify_goods.py

(废弃)例子:

目录如下:

project
|---main.py
|---school
    |----__init__.py
    |---view.py
    |---classes
        |----__init__.py
        |----view.py
    |---student
        |----__init__.py
        |----view.py
|---room(寝室)
    |----__init__.py
    |---view.py

1.main.py
启动文件。
注意:
在不同包之间import模块,启动文件位置很重要,否则执行时会报错

2.school.__init__.py,代码如下:

#coding=utf-8

print('school.__init__.py')

3.school.view.py,代码如下:

def show():
    print('学校信息')

4.school.classes.__init__.py,代码如下:

#coding=utf-8

print('classes.__init__.py')

5.school.classes.view.py,代码如下:

#coding=utf-8

def show():
    print('班级信息')

6.school.student.__init__.py,代码如下:

# encode=utf-8

print('student.__init__.py')

7.school.student.view.py,代码如下:

# encode=utf-8

def show():
    print('学生信息')

8.room.__init__.py,代码如下:

#coding=utf-8

print('room.__init__.py')

9.room.view.py,代码如下

# encode=utf-8

def show():
    print('寝室信息')

实验

1.main.py导入school.view模块
代码如下:

#coding=utf-8

from school import view

或者

#coding=utf-8

import school.view

执行main.py结果如下:

school.__init__.py

在导入school包时,就调用school包下的 __init__.py

2.main.py调用school.view的show()函数

#coding=utf-8
#从shool包中导入view模块,之后可以直接使用view
from school import view

view.show()

或者

#coding=utf-8
#导入school.view模块,后面都要用school.view
import school.view

school.view.show()

执行main.py结果如下:

school.__init__.py
学校信息

3.接着上面代码,main.py导入school.classes.view模块
代码如下:

#coding=utf-8

from school import view
from school.classes import view

view.show()

执行main.py结果如下:

school.__init__.py
classes.__init__.py
班级信息

由于两次import view,导致后面的view覆盖了上面的from school import view,所以打印的结果是“班级信息”,而不是“学校信息”,
所以在导入包时要注意,为了 避免同名 情况,可以使用as关键字 起别名,改动如下:

#coding=utf-8

from school import view
#通过as关键字起别名
from school.classes import view as cview

view.show()
cview.show()

执行main.py结果如下:

school.__init__.py
classes.__init__.py
学校信息
班级信息

在导入school、classes包时,就调用school和classes包下的 __init__.py

3.school.view.py导入school.student.view模块
学校模块中,需要调用学生模块的功能,此时就需要导入不同包的模块,
school.view.py代码如下:

# encode=utf-8

#增加导入student.view模块
from .student import view #.student表示与当前文件同级的student包

def show():
    print('学校信息')
    view.show()

执行 school.view.py 结果:

ModuleNotFoundError: No module named '__main__.student'; '__main__' is not a package

报错了

注意:

在导入不同包的模块时,要有入口文件,不能随意执行py文件,会报错

执行 main.py 结果:

school.__init__.py
student.__init__.py
classes.__init__.py
学校信息
学生信息
班级信息

4.school.student.view.py导入room.view模块
school.student.view.py代码如下:

# encode=utf-8

#增加导入room.view模块,..room表示当前文件的上一个目录下的room包
from ..room import view

def show():
    print('学生信息')

或者

# encode=utf-8

#增加导入room.view模块,此处是全路径
from school.room import view

def show():
    print('学生信息')

执行结果

school.__init__.py
student.__init__.py
room.__init__.py
classes.__init__.py
学校信息
学生信息
班级信息

5.school.student.view.py调用room.view的show()函数
school.student.view.py代码如下:

# encode=utf-8

#增加导入room.view模块,..room表示当前文件的上一个目录下的room包
from ..room import view

def show():
    print('学生信息')
    #增加调用函数代码
    view.show()

执行 main.py 结果:

school.__init__.py
student.__init__.py
room.__init__.py
classes.__init__.py
学校信息
学生信息
寝室信息
班级信息

感谢:
http://www.cnblogs.com/ArsenalfanInECNU/p/5346751.html


原文出处:/show_1EF1Srv34PGJ.html